]> git.neil.brown.name Git - history.git/commitdiff
v2.4.5.5 -> v2.4.5.6
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 02:48:22 +0000 (18:48 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 02:48:22 +0000 (18:48 -0800)
  - Jeff Garzik: net driver updates, PCI PM induced cleanups
  - Me: do ACPI first, so that it doesn't mess up existing device driver
  configurations.  Notably it used to completely destroy PCMCIA on some
  Sony VAIOs.
  - Paul Mackerras: powermac drivers and MAINTAINERS update
  - NIIBE Yutaka: SuperH update
  - Johannes Erdfelt: USB driver updates
  - Russell King: ARM update
  - Alan Cox: merging, merging, merging

264 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/java.txt
Documentation/usb/se401.txt [new file with mode: 0644]
Documentation/usb/usb-serial.txt
MAINTAINERS
Makefile
arch/alpha/kernel/sys_alcor.c
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head-integrator.S [new file with mode: 0644]
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/setup-sa1100.S
arch/arm/kernel/calls.S
arch/arm/kernel/ecard.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/fiq.c
arch/arm/kernel/sys_arm.c
arch/arm/kernel/traps.c
arch/arm/mach-ebsa110/arch.c
arch/arm/mach-ebsa110/hardware.h [new file with mode: 0644]
arch/arm/mach-ebsa110/io.c
arch/arm/mm/consistent.c
arch/arm/mm/fault-armv.c
arch/arm/mm/mm-armv.c
arch/arm/mm/mm-l7200.c
arch/arm/tools/Makefile
arch/arm/tools/getconstants.c
arch/arm/tools/mach-types
arch/i386/defconfig
arch/i386/kernel/bluesmoke.c
arch/sh/config.in
arch/sh/kernel/Makefile
arch/sh/kernel/entry.S
arch/sh/kernel/hd64465_gpio.c
arch/sh/kernel/io_bigsur.c [new file with mode: 0644]
arch/sh/kernel/io_dc.c
arch/sh/kernel/io_hd64465.c
arch/sh/kernel/io_sh2000.c [new file with mode: 0644]
arch/sh/kernel/irq.c
arch/sh/kernel/irq_intc2.c
arch/sh/kernel/irq_ipr.c
arch/sh/kernel/led_bigsur.c [new file with mode: 0644]
arch/sh/kernel/mach_bigsur.c [new file with mode: 0644]
arch/sh/kernel/mach_dc.c
arch/sh/kernel/pci-7751se.c [new file with mode: 0644]
arch/sh/kernel/pci-bigsur.c [new file with mode: 0644]
arch/sh/kernel/pci-dc.c [new file with mode: 0644]
arch/sh/kernel/pci-dma.c [new file with mode: 0644]
arch/sh/kernel/pci-sh.c [deleted file]
arch/sh/kernel/pci-sh7751.c [new file with mode: 0644]
arch/sh/kernel/pci_st40.c
arch/sh/kernel/rtc.c
arch/sh/kernel/setup.c
arch/sh/kernel/setup_bigsur.c [new file with mode: 0644]
arch/sh/kernel/setup_dc.c
arch/sh/kernel/setup_od.c [deleted file]
arch/sh/kernel/setup_sh2000.c [new file with mode: 0644]
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/time.c
arch/sh/mm/cache.c
arch/sh/mm/fault.c
arch/sh/mm/init.c
arch/sh/stboards/Makefile [new file with mode: 0644]
arch/sh/stboards/harp.h [new file with mode: 0644]
arch/sh/stboards/irq.c [new file with mode: 0644]
arch/sh/stboards/led.c [new file with mode: 0644]
arch/sh/stboards/mach.c [new file with mode: 0644]
arch/sh/stboards/pcidma.c [new file with mode: 0644]
arch/sh/stboards/setup.c [new file with mode: 0644]
arch/sparc64/config.in
arch/sparc64/defconfig
drivers/acorn/char/keyb_arc.c
drivers/acorn/char/keyb_ps2.c
drivers/acorn/char/mouse_ps2.c [new file with mode: 0644]
drivers/acorn/char/mouse_rpc.c
drivers/acorn/net/ether1.c
drivers/acorn/net/ether3.c
drivers/acorn/scsi/acornscsi.c
drivers/acorn/scsi/acornscsi.h
drivers/acpi/os.c
drivers/atm/ambassador.c
drivers/atm/fore200e.c
drivers/atm/idt77105.c
drivers/atm/iphase.c
drivers/atm/nicstar.c
drivers/atm/uPD98402.c
drivers/atm/zatm.c
drivers/block/cciss.c
drivers/block/paride/pt.c
drivers/block/ps2esdi.c
drivers/block/swim3.c
drivers/cdrom/mcdx.c
drivers/char/agp/agpgart_fe.c
drivers/char/cyclades.c
drivers/char/drm/context.c
drivers/char/drm/dma.c
drivers/char/drm/i810_dma.c
drivers/char/drm/mga_state.c
drivers/char/drm/proc.c
drivers/char/drm/radeon_bufs.c
drivers/char/epca.c
drivers/char/esp.c
drivers/char/i810-tco.c
drivers/char/n_r3964.c
drivers/char/nvram.c
drivers/char/nwflash.c
drivers/char/raw.c
drivers/char/sbc60xxwdt.c
drivers/char/sh-sci.c
drivers/char/sh-sci.h
drivers/char/sx.c
drivers/char/sx.h
drivers/char/tty_io.c
drivers/ide/hpt366.c
drivers/ide/ide-pci.c
drivers/ide/rapide.c
drivers/ide/sl82c105.c
drivers/isdn/avmb1/c4.c
drivers/isdn/avmb1/capi.c
drivers/isdn/avmb1/kcapi.c
drivers/isdn/eicon/common.c
drivers/isdn/eicon/linchr.c
drivers/macintosh/mac_hid.c
drivers/macintosh/mac_keyb.c
drivers/macintosh/macserial.c
drivers/macintosh/macserial.h
drivers/media/video/i2c-parport.c
drivers/media/video/planb.c
drivers/media/video/planb.h
drivers/media/video/videodev.c
drivers/media/video/zr36120.c
drivers/mtd/Config.in
drivers/net/3c509.c
drivers/net/Config.in
drivers/net/am79c961a.c
drivers/net/appletalk/ipddp.c
drivers/net/dmfe.c
drivers/net/ewrk3.c
drivers/net/fealnx.c
drivers/net/hamradio/bpqether.c
drivers/net/hamradio/scc.c
drivers/net/hamradio/soundmodem/sm.h
drivers/net/hamradio/soundmodem/sm_wss.c
drivers/net/natsemi.c
drivers/net/shaper.c
drivers/net/sis900.c
drivers/net/sundance.c
drivers/net/tokenring/smctr.c
drivers/net/wan/comx-hw-mixcom.c
drivers/net/wan/comx-proto-fr.c
drivers/net/wan/cosa.c
drivers/net/wan/lapbether.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wan/syncppp.c
drivers/net/winbond-840.c
drivers/nubus/nubus.c
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h
drivers/scsi/NCR53c406a.c
drivers/scsi/aha152x.c
drivers/scsi/dmx3191d.c
drivers/scsi/dmx3191d.h
drivers/scsi/eata_dma.c
drivers/scsi/hosts.c
drivers/scsi/qla1280.c
drivers/scsi/scsi_proc.c
drivers/scsi/sym53c416.c
drivers/scsi/sym53c416.h
drivers/sound/cmpci.c
drivers/sound/cs4281/cs4281m.c
drivers/sound/cs46xx.c
drivers/sound/cs46xxpm-24.h
drivers/sound/maestro3.c
drivers/sound/sb_card.c
drivers/sound/wavfront.c
drivers/sound/wf_midi.c
drivers/telephony/ixj.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/pegasus.c
drivers/usb/pegasus.h
drivers/usb/se401.c [new file with mode: 0644]
drivers/usb/se401.h [new file with mode: 0644]
drivers/usb/serial/Config.in
drivers/usb/serial/Makefile
drivers/usb/serial/cyberjack.c [new file with mode: 0644]
drivers/usb/serial/pl2303.c [new file with mode: 0644]
drivers/usb/usb-ohci.c
drivers/usb/usb-uhci.c
drivers/video/cyber2000fb.c
drivers/video/imsttfb.c
drivers/video/macmodes.c
drivers/video/matrox/matroxfb_DAC1064.c
drivers/video/matrox/matroxfb_Ti3026.c
drivers/video/matrox/matroxfb_accel.c
drivers/video/matrox/matroxfb_base.c
drivers/video/matrox/matroxfb_base.h
drivers/video/matrox/matroxfb_g450.c
drivers/video/mdacon.c
fs/freevxfs/vxfs_bmap.c
fs/freevxfs/vxfs_fshead.h
fs/freevxfs/vxfs_inode.c
fs/freevxfs/vxfs_inode.h
fs/freevxfs/vxfs_lookup.c
fs/freevxfs/vxfs_super.c
fs/jffs/inode-v23.c
fs/nls/Config.in
fs/proc/base.c
fs/proc/generic.c
fs/select.c
include/asm-arm/bitops.h
include/asm-arm/io.h
include/asm-arm/pci.h
include/asm-arm/proc-armo/system.h
include/asm-arm/proc-armv/system.h
include/asm-arm/xor.h
include/asm-sh/bigsur.h [new file with mode: 0644]
include/asm-sh/bitops.h
include/asm-sh/bugs.h
include/asm-sh/dc_sysasic.h [new file with mode: 0644]
include/asm-sh/hardirq.h
include/asm-sh/hd64465_gpio.h
include/asm-sh/io.h
include/asm-sh/io_bigsur.h [new file with mode: 0644]
include/asm-sh/io_od.h [deleted file]
include/asm-sh/io_sh2000.h [new file with mode: 0644]
include/asm-sh/irq.h
include/asm-sh/machvec.h
include/asm-sh/mc146818rtc.h [new file with mode: 0644]
include/asm-sh/pci-sh7751.h [new file with mode: 0644]
include/asm-sh/pci.h
include/asm-sh/pgalloc.h
include/asm-sh/pgtable-2level.h
include/asm-sh/pgtable.h
include/asm-sh/processor.h
include/asm-sh/rtc.h
include/asm-sh/semaphore.h
include/asm-sh/serial-bigsur.h [new file with mode: 0644]
include/asm-sh/serial.h
include/asm-sh/softirq.h
include/asm-sh/string.h
include/asm-sh/user.h
include/linux/mii.h
include/linux/sockios.h
include/video/macmodes.h
kernel/sched.c
mm/page_alloc.c
mm/vmscan.c
net/atm/clip.c
net/atm/common.c
net/atm/lec.c
net/atm/mpc.c
net/atm/signaling.c
net/decnet/af_decnet.c
net/netlink/af_netlink.c
net/netrom/nr_dev.c
net/netrom/nr_loopback.c
net/netrom/nr_subr.c
net/rose/rose_dev.c
net/wanrouter/wanmain.c
net/wanrouter/wanproc.c

diff --git a/CREDITS b/CREDITS
index 5fde33453675acc52d100844d89d9f5aeaae0d00..67ed15ec9ed5f8ed1b63210b812cbc7e08829f6a 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -454,6 +454,11 @@ N: Gary Brubaker
 E: xavyer@ix.netcom.com
 D: USB Serial Empeg Empeg-car Mark I/II Driver
 
+N: Matthias Bruestle
+E: m@mbsks.franken.de
+D: REINER SCT cyberJack pinpad/e-com USB chipcard reader driver
+S: Germany
+
 N: Ray Burr
 E: ryb@nightmare.com
 D: Original author of Amiga FFS filesystem
@@ -1136,13 +1141,11 @@ S: Mountain View, California 94041
 S: USA
 
 N: Benjamin Herrenschmidt
-E: bh40@calva.net
+E: benh@kernel.crashing.org
 E: benh@mipsys.com
-D: PowerMac booter (BootX)
-D: Additional PowerBook support
-D: Apple "Core99" machines support (ibook,g4,...)
-S: 22, rue des Marguettes
-S: 75012 Paris
+D: Various parts of PPC & PowerMac
+S: 122, boulevard Baille
+S: 13005 Marseille
 S: France
 
 N: Sebastian Hetze
@@ -1755,6 +1758,8 @@ S: Czech Republic
 
 N: Paul Mackerras
 E: paulus@samba.org
+D: PPP driver
+D: Linux for PowerPC
 D: Linux port for PCI Power Macintosh
 
 N: Pat Mackinlay
@@ -2896,6 +2901,14 @@ S: Kruislaan 419
 S: 1098 VA Amsterdam 
 S: The Netherlands
 
+N: Jeroen Vreeken
+E: pe1rxq@amsat.org
+W: http://www.chello.nl/~j.vreeken/
+D: SE401 usb webcam driver
+S: Maastrichterweg 63
+S: 5554 GG Valkenswaard
+S: The Netherlands
+
 N: Peter Shaobo Wang
 E: pwang@mmdcorp.com
 W: http://www.mmdcorp.com/pw/linux
index 7a5dbc864b5bc233dc433df99fdce26ae0724977..65bc2ac4dcf2732047ec2919265f9d087c085633 100644 (file)
@@ -347,7 +347,7 @@ Network
 
 PPP
 ---
-o  <ftp://ftp.samba.org/ppp/ppp-2.4.0.tar.gz>
+o  <ftp://ftp.samba.org/pub/ppp/ppp-2.4.0.tar.gz>
 
 Isdn4k-utils
 ------------
index e46852c2704593b56c28ea23fcce9c9cbb5a04a4..fd1366108374d33b183f9c07d03f1fdf15028f36 100644 (file)
@@ -11243,6 +11243,29 @@ CONFIG_USB_SERIAL_MCT_U232
   The module will be called mct_u232.o.  If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
+USB Prolific 2303 Single Port Serial Driver
+CONFIG_USB_SERIAL_PL2303
+  Say Y here if you want to use the PL2303 USB Serial single port
+  adapter from Prolific.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pl2303.o.  If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+USB REINER SCT cyberJack pinpad/e-com chipcard reader
+CONFIG_USB_SERIAL_CYBERJACK
+  Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
+  reader. This is an interface to ISO 7816 compatible contactbased
+  chipcards, e.g. GSM SIMs.
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cyberjack.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+  If unsure, say N.
+
 USB Edgeport Serial Driver
 CONFIG_USB_SERIAL_EDGEPORT
   Say Y here if you want to use any of the following devices from
@@ -11348,6 +11371,22 @@ CONFIG_USB_PWC
   module, say M here and read Documentation/modules.txt.
 
 
+USB SE401 Camera support
+CONFIG_USB_SE401
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See Documentation/usb/se401.txt for more
+  information and for a list of supported cameras.
+  
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml .
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called se401.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 USB ADMtek Pegasus-based ethernet device support
 CONFIG_USB_PEGASUS
   Say Y if you want to use your USB ethernet device. Supported
index be7203d3b0a1ef479d5d9ac493e6fbe98d9fcc74..4a4f0e118b9b697d969405b06532e6a6837842d0 100644 (file)
@@ -1,4 +1,4 @@
-               Java(tm) Binary Kernel Support for Linux v1.02
+               Java(tm) Binary Kernel Support for Linux v1.03
                ----------------------------------------------
 
 Linux beats them ALL! While all other OS's are TALKING about direct
@@ -30,6 +30,8 @@ other program after you have done the following:
    (you should really have read binfmt_misc.txt now):
    support for Java applications:
      ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:'
+   support for executable Jar files:
+     ':ExecutableJAR:E::jar::/usr/local/bin/jarwrapper:'
    support for Java Applets:
      ':Applet:E::html::/usr/bin/appletviewer:'
    or the following, if you want to be more selective:
@@ -343,7 +345,15 @@ int main(int argc, char **argv)
 ====================== Cut here ===================
 
 
-Now simply chmod +x the .class and/or .html files you want to execute.
+====================== Cut here ===================
+#!/bin/bash
+# /usr/local/java/bin/jarwrapper - the wrapper for binfmt_misc/jar
+
+java -jar $1
+====================== Cut here ===================
+
+
+Now simply chmod +x the .class, .jar and/or .html files you want to execute.
 To add a Java program to your path best put a symbolic link to the main
 .class file into /usr/bin (or another place you like) omitting the .class
 extension. The directory containing the original .class file will be
@@ -369,6 +379,11 @@ And then execute it:
        ./HelloWorld.class
 
 
+To execute Java Jar files, simple chmod the *.jar files to include
+the execution bit, then just do
+       ./Application.jar
+
+
 To execute Java Applets, simple chmod the *.html files to include
 the execution bit, then just do
        ./Applet.html
@@ -376,5 +391,6 @@ the execution bit, then just do
 
 originally by Brian A. Lantz, brian@lantz.com
 heavily edited for binfmt_misc by Richard Günther
-new scripts by Colin J. Watson <cjw44@cam.ac.uk>.
+new scripts by Colin J. Watson <cjw44@cam.ac.uk>
+added executable Jar file support by Kurt Huwig <kurt@iku-netz.de>
 
diff --git a/Documentation/usb/se401.txt b/Documentation/usb/se401.txt
new file mode 100644 (file)
index 0000000..46c9bc5
--- /dev/null
@@ -0,0 +1,54 @@
+Linux driver for SE401 based USB cameras
+
+Copyright, 2001, Jeroen Vreeken
+
+
+INTRODUCTION:
+
+The SE401 chip is the used in low-cost usb webcams.
+It is produced by Endpoints Inc. (www.endpoints.com).
+It interfaces directly to a cmos image sensor and USB. The only other major
+part in a se401 based camera is a dram chip.
+
+The following cameras are known to work with this driver:
+
+Aox se401 (non-branded) cameras
+Philips PVCV665 USB VGA webcam 'Vesta Fun'
+Kensington VideoCAM PC Camera Model 67014
+Kensington VideoCAM PC Camera Model 67015
+Kensington VideoCAM PC Camera Model 67016
+Kensington VideoCAM PC Camera Model 67017
+
+
+WHAT YOU NEED:
+
+-      USB support
+-      VIDEO4LINUX support
+
+More information about USB support for linux can be found at:
+http://www.linux-usb.org
+
+
+MODULE OPTIONS:
+
+When the driver is compiled as a module you can also use the 'flickerless'
+option. With it exposure is limited to values that do not interfere with the
+net frequency. Valid options for this option are 0, 50 and 60. (0=disable,
+50=50hz, 60=60hz)
+
+
+KNOWN PROBLEMS:
+
+The driver works fine with the usb-ohci and uhci host controller drivers,
+the default settings also work with usb-uhci. But sending more then one bulk
+transfer at a time with usb-uhci doesn't work yet.
+Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in
+order to increase the throughput (and thus framerate).
+
+
+HELP:
+
+The latest info on this driver can be found at:
+http://www.chello.nl/~j.vreeken/se401/
+And questions to me can be send to:
+pe1rxq@amsat.org
index b4483a802b089f4950a243889ef6a530c122d638..06a734a31eb6dad1d042da24ab740bb5a2029feb 100644 (file)
@@ -245,6 +245,17 @@ Inside Out Networks Edgeport Driver
        Edgeport/16 Dual
 
 
+REINER SCT cyberJack pinpad/e-com USB chipcard reader
+   
+  Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs.
+  
+Current status:
+  This is the kernel part of the driver for this USB card reader.
+  There is also a user part for a CT-API driver available. A site
+  for downloading is TBA. For now, you can request it from the
+  maintainer (linux-usb@sii.li).
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
index e3e38eee861092c2b8703b763aea4e60bfc5788e..8b3de51297b8b423381137ea6daf391f7528d62d 100644 (file)
@@ -784,15 +784,21 @@ M:        eis@baty.hanse.de
 L:     linux-x25@vger.kernel.org
 S:     Maintained
 
+LINUX FOR IBM pSERIES (RS/6000)
+P:     Paul Mackerras
+M:     paulus@au.ibm.com
+W:     http://www.ibm.com/linux/ltc/projects/ppc
+S:     Supported
+
 LINUX FOR POWERPC
-P:     Cort Dougan
-M:     cort@fsmlabs.com
+P:     Paul Mackerras
+M:     paulus@samba.org
 W:     http://www.fsmlabs.com/linuxppcbk.html
-S:     Maintained
+S:     Supported
 
 LINUX FOR POWER MACINTOSH
-P:     Paul Mackerras
-M:     paulus@samba.org
+P:     Benjamin Herrenschmidt
+M:     benh@kernel.crashing.org
 W:     http://www.linuxppc.org/
 L:     linuxppc-dev@lists.linuxppc.org
 S:     Maintained
@@ -1462,6 +1468,12 @@ L:       linux-usb-users@lists.sourceforge.net
 L:     linux-usb-devel@lists.sourceforge.net
 S:     Maintained
 
+USB SERIAL CYBERJACK PINPAD/E-COM DRIVER
+M:  linux-usb@sii.li
+L:  linux-usb-users@lists.sourceforge.net
+L:  linux-usb-devel@lists.sourceforge.net
+S:  Supported
+
 USB MASS STORAGE DRIVER
 P:     Matthew Dharm
 M:     mdharm-usb@one-eyed-alien.net
index e38aac2234bca35f3e843558b401418d4dc9c8b3..96da0f2b35e47cf2690d542449651f27473a1641 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 6
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -128,6 +128,7 @@ DRIVERS-y :=
 DRIVERS-m :=
 DRIVERS-  :=
 
+DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
 DRIVERS-y += drivers/char/char.o \
        drivers/block/block.o \
@@ -177,7 +178,6 @@ DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o
 DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
-DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
 DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
 
index 5b764298a2d9dada3b6555d3d0a43a6d6a179ec3..aec3d088f12d5d4b168d92cb60f69744a01da257 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -219,11 +220,21 @@ alcor_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 static void
 alcor_kill_arch(int mode)
 {
-       /* Who said DEC engineer's have no sense of humor? ;-)  */
-       if (alpha_using_srm) {
-               *(vuip) GRU_RESET = 0x0000dead;
-               mb();
+       switch(mode) {
+       case LINUX_REBOOT_CMD_RESTART:
+               /* Who said DEC engineer's have no sense of humor? ;-)  */
+               if (alpha_using_srm) {
+                       *(vuip) GRU_RESET = 0x0000dead;
+                       mb();
+               }
+               break;
+       case LINUX_REBOOT_CMD_HALT:
+               break;
+       case LINUX_REBOOT_CMD_POWER_OFF:
+               break;
        }
+
+       halt();
 }
 
 
index e0287907a4787f9fbff85fef3e06fc1c3cc16398..7debc667a2539ad2aebe687852c5cc7cc5f9b8b5 100644 (file)
@@ -26,7 +26,7 @@ apcs-y                                :=
 apcs-$(CONFIG_CPU_26)          :=-mcpu=arm3 -Os
 
 arch-y                         :=
-arch-$(CONFIG_CPU_32v3)                :=-march=armv3m
+arch-$(CONFIG_CPU_32v3)                :=-march=armv3
 arch-$(CONFIG_CPU_32v4)                :=-march=armv4
 arch-$(CONFIG_CPU_32v5)                :=-march=armv5
 
@@ -123,6 +123,10 @@ TEXTADDR    = 0xc0018000
 MACHINE                 = clps711x
 endif
 
+ifeq ($(CONFIG_ARCH_ANAKIN),y)
+MACHINE                 = anakin
+endif
+
 export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS
 
 # Only set INCDIR if its not already defined above
@@ -156,7 +160,7 @@ ifeq ($(CONFIG_FPE_FASTFPE),y)
 LIBS           := arch/arm/fastfpe/fast-math-emu.o $(LIBS)
 endif
 
-ifeq ($(CONFIG_ARCH_CLPS7500),y)
+ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y)
 SUBDIRS                += drivers/acorn/char
 DRIVERS                += drivers/acorn/char/acorn-char.o
 endif
@@ -237,8 +241,8 @@ bp:;        @$(MAKEBOOT) bootpImage
        @( \
        CFG=$(@:_config=); \
        if [ -f arch/arm/def-configs/$$CFG ]; then \
-         $(RM) arch/arm/defconfig; \
-         cp arch/arm/def-configs/$$CFG arch/arm/defconfig; \
+         [ -f .config ] && $(MV) .config .config.old; \
+         cp arch/arm/def-configs/$$CFG .config; \
          echo "*** Default configuration for $$CFG installed"; \
          echo "*** Next, you may run 'make oldconfig'"; \
        else \
index a2a540e82228d6df2bb344a5e341feb367b9140b..4dc9ec85ae5487f0d587b6e885c8c2d4be9167fb 100644 (file)
@@ -90,11 +90,19 @@ endif
 ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
   ZTEXTADDR     = 0xC0200000
 endif
+ifeq ($(CONFIG_SA1100_YOPY),y)
+  ZTEXTADDR      = 0x00080000
+  ZBSSADDR       = 0xc0200000
+endif
 ifeq ($(CONFIG_SA1111),y)
   ZRELADDR      = 0xc0208000
 endif
 endif
 
+ifeq ($(CONFIG_ARCH_ANAKIN),y)
+ZTEXTADDR       = 0x20008000
+endif
+
 #
 # If you don't define ZRELADDR above,
 # then it defaults to ZTEXTADDR
index 4535d005c625095ee36f13ceefc162f87187155a..d61994c5a8ed3919837dcbba16410523918de672 100644 (file)
@@ -30,7 +30,7 @@ OBJS          += head-shark.o ofw-shark.o
 endif
 
 ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
-OBJS           += head-netwinder.o
+OBJS           += head-integrator.o
 endif
 
 ifeq ($(CONFIG_ARCH_FTVPCI),y)
diff --git a/arch/arm/boot/compressed/head-integrator.S b/arch/arm/boot/compressed/head-integrator.S
new file mode 100644 (file)
index 0000000..0f901b7
--- /dev/null
@@ -0,0 +1,4 @@
+#include <asm/mach-types.h>
+
+               .section        ".start", #alloc, #execinstr
+               mov     r7, #MACH_TYPE_INTEGRATOR
index da88c79e120de1d60bee724e6d39ef6709f10076..d71d40142a62214f1e6de7ebff6f4870fad105bd 100644 (file)
 
 /*
  * Debugging stuff
+ *
+ * Note that these macros must not contain any code which is not
+ * 100% relocatable.  Any attempt to do so will result in a crash.
+ * Please select one of the following when turning on debugging.
  */
+#ifdef DEBUG
+#if 0 /* DC21285-type */
+               .macro  loadsp, rb
+               mov     \rb, #0x7c000000
+               .endm
+               .macro  writeb, rb
+               strb    \rb, [r3, #0x3f8]
+               .endm
+#elif 0 /* RiscPC-type */
+               .macro  loadsp, rb
+               mov     \rb, #0x03000000
+               orr     \rb, \rb, #0x00010000
+               .endm
+               .macro  writeb, rb
+               strb    \rb, [r3, #0x3f8 << 2]
+               .endm
+#elif 0 /* integrator-type */
+               .macro  loadsp, rb
+               mov     \rb, #0x16000000
+               .endm
+               .macro  writeb, rb
+               strb    \rb, [r3, #0]
+               .endm
+#else
+#error no serial architecture defined
+#endif
+#endif
+
                .macro  kputc,val
                mov     r0, \val
                bl      putc
                .macro  debug_reloc_start
 #ifdef DEBUG
                kputc   #'\n'
-               kphex   r6, 8
+               kphex   r6, 8           /* processor id */
                kputc   #':'
-               kphex   r5, 8
+               kphex   r7, 8           /* architecture id */
+               kputc   #':'
+               mrc     p15, 0, r0, c1, c0
+               kphex   r0, 8           /* control reg
+               kputc   #'\n'
+               kphex   r5, 8           /* decompressed kernel start */
                kputc   #'-'
-               kphex   r8, 8
+               kphex   r8, 8           /* decompressed kernel end  */
                kputc   #'>'
-               kphex   r4, 8
+               kphex   r4, 8           /* kernel execution address */
                kputc   #'\n'
 #endif
                .endm
 
                .macro  debug_reloc_end
 #ifdef DEBUG
-               mov     r8, r0
-               kphex   r5, 8
-               kputc   #'-'
-               kphex   r8, 8
+               kphex   r5, 8           /* end of kernel */
                kputc   #'\n'
                mov     r0, r4
-               bl      memdump
+               bl      memdump         /* dump 256 bytes at start of kernel */
 #endif
                .endm
 
-/*
- * Note that these macros must not contain any code which is not
- * 100% relocatable.  Any attempt to do so will result in a crash.
- */
-#if 0
-               .macro  loadsp, rb
-               mov     \rb, #0x7c000000
-               .endm
-
-               .macro  writeb, rb
-               strb    \rb, [r3, #0x3f8]
-               .endm
-#else
-               .macro  loadsp, rb
-               mov     \rb, #0x03000000
-               orr     \rb, \rb, #0x00010000
-               .endm
-
-               .macro  writeb, rb
-               strb    \rb, [r3, #0x3f8 << 2]
-               .endm
-#endif
-
-
                .section ".start", #alloc, #execinstr
 /*
  * sort out different calling conventions
@@ -91,14 +101,18 @@ start:
                .word   _edata                  @ zImage end address
 1:             mov     r7, r1                  @ save architecture ID
                mov     r8, #0                  @ save r0
-#ifdef CONFIG_ANGELBOOT
+
                /*
                 * Booting from Angel - need to enter SVC mode and disable
-                * FIQs/IRQs (numeric definitions from angel arm.h source)
+                * FIQs/IRQs (numeric definitions from angel arm.h source).
+                * We only do this if we were in user mode on entry.
                 */
+               mrs     r0, cpsr                @ get current mode
+               tst     r0, #3                  @ not user?
+               bne     not_angel
                mov     r0, #0x17               @ angel_SWIreason_EnterSVC
                swi     0x123456                @ angel_SWI_ARM
-               mrs     r0, cpsr                @ turn off interrupts to
+not_angel:     mrs     r0, cpsr                @ turn off interrupts to
                orr     r0, r0, #0xc0           @ prevent angel from running
                msr     cpsr_c, r0
 
@@ -106,7 +120,7 @@ start:
                 * Note that some cache flushing and other stuff may
                 * be needed here - is there an Angel SWI call for this?
                 */
-#endif
+
                /*
                 * some architecture specific code can be inserted
                 * by the linker here, but it should preserve r7 and r8.
@@ -300,30 +314,46 @@ proc_sa1110_type:
                .size   proc_sa1110_type, . - proc_sa1110_type
 
 /*
- * Turn off StrongARM cache and MMU.  It is safe to
- * leave the I-cache on.
+ * Turn off the Cache and MMU.  ARMv3 does not support
+ * reading the control register, but ARMv4 does.
  *
- * On entry,
- *  r6 = processor ID
- * On exit,
- *  r0, r1 corrupted
- * This routine must preserve:
- *  r4, r6, r7
+ * On entry,  r6 = processor ID
+ * On exit,   r0, r1 corrupted
+ * This routine must preserve: r4, r6, r7
  */
                .align  5
-cache_off:     ldr     r1, proc_sa110_type
-               eor     r1, r1, r6
-               movs    r1, r1, lsr #5          @ catch SA110 and SA1100
-               beq     1f
-               ldr     r1, proc_sa1110_type
-               eor     r1, r1, r6
-               movs    r1, r1, lsr #4
-               movne   pc, lr
-1:
+cache_off:
+#ifdef CONFIG_CPU_ARM610
+               eor     r1, r6, #0x41000000
+               eor     r1, r1, #0x00560000
+               bic     r1, r1, #0x0000001f
+               teq     r1, #0x00000600
+               mov     r0, #0x00000060         @ ARM6 control reg.
+               beq     __armv3_cache_off
+#endif
+#ifdef CONFIG_CPU_ARM710
+               eor     r1, r6, #0x41000000
+               bic     r1, r1, #0x00070000
+               bic     r1, r1, #0x000000ff
+               teq     r1, #0x00007000         @ ARM7
+               teqne   r1, #0x00007100         @ ARM710
+               mov     r0, #0x00000070         @ ARM7 control reg.
+               beq     __armv3_cache_off
+#endif
                mrc     p15, 0, r0, c1, c0
                bic     r0, r0, #0x000d
-               mcr     p15, 0, r0, c1, c0
-               mov     pc, lr          
+               mcr     p15, 0, r0, c1, c0      @ turn MMU and cache off
+               mov     r0, #0
+               mcr     p15, 0, r0, c7, c7      @ invalidate whole cache v4
+               mcr     p15, 0, r0, c8, c7      @ invalidate whole TLB v4
+               mov     pc, lr
+
+__armv3_cache_off:
+               mcr     p15, 0, r0, c1, c0      @ turn MMU and cache off
+               mov     r0, #0
+               mcr     p15, 0, r0, c7, c0      @ invalidate whole cache v3
+               mcr     p15, 0, r0, c5, c0      @ invalidate whole TLB v3
+               mov     pc, lr
 
 /*
  * Clean and flush the cache to maintain consistency.
@@ -401,13 +431,10 @@ putc:
 
 memdump:       mov     r12, r0
                mov     r10, lr
-               mov     r1, #8
-               bl      phex
-               mov     r0, #'\n'
-               bl      putc
                mov     r11, #0
 2:             mov     r0, r11, lsl #2
-               mov     r1, #4
+               add     r0, r0, r12
+               mov     r1, #8
                bl      phex
                mov     r0, #':'
                bl      putc
index 63a2c8f84d7e16d75bf94feb55306fb1ffe6e39f..87a25b6247ba7a9c17698e1f84ce4fed104370e0 100644 (file)
                .text
 
 GPIO_BASE:     .long   0x90040000
-#define GPLR   0x00
-#define GPDR   0x04
-#define GPSR   0x08
-#define GAFR   0x1c
+#define GPLR           0x00
+#define GPDR           0x04
+#define GPSR           0x08
+#define GAFR           0x1c
 
 PPC_BASE:      .long   0x90060000
-#define PPAR   0x08
+#define PPAR           0x08
 
 IC_BASE:       .long   0x90050000
-#define ICMR   0x04
+#define ICMR           0x04
 
 UART1_BASE:    .long   0x80010000
 UART3_BASE:    .long   0x80050000
@@ -95,7 +95,11 @@ skip_SCR:
                @ Initialize UART (if bootloader has not done it yet)...
                teq     r3, #MACH_TYPE_BRUTUS
                teqne   r3, #MACH_TYPE_ASSABET
+               teqne   r3, #MACH_TYPE_ITSY
+               teqne   r3, #MACH_TYPE_OMNIMETER
+               teqne   r3, #MACH_TYPE_JORNADA720
                teqne   r3, #MACH_TYPE_GRAPHICSCLIENT
+               teqne   r3, #MACH_TYPE_FLEXANET
                bne     skip_uart
 
                @ UART3 if Assabet is used with Neponset
index 9d672b4e9c6d631073e2022f63ac8f326a8d21a0..cfc646968e83044b52be40e960dce4790a156a94 100644 (file)
@@ -13,6 +13,7 @@
 #define NR_syscalls 256
 #else
 
+__syscall_start:
 /* 0 */                .long   SYMBOL_NAME(sys_ni_syscall)
                .long   SYMBOL_NAME(sys_exit)
                .long   SYMBOL_NAME(sys_fork_wrapper)
 /* 160 */      .long   SYMBOL_NAME(sys_sched_get_priority_min)
                .long   SYMBOL_NAME(sys_sched_rr_get_interval)
                .long   SYMBOL_NAME(sys_nanosleep)
-               .long   SYMBOL_NAME(sys_mremap)
+               .long   SYMBOL_NAME(sys_arm_mremap)
                .long   SYMBOL_NAME(sys_setresuid16)
 /* 165 */      .long   SYMBOL_NAME(sys_getresuid16)
                .long   SYMBOL_NAME(sys_ni_syscall)
 /* 215 */      .long   SYMBOL_NAME(sys_setfsuid)
                .long   SYMBOL_NAME(sys_setfsgid)
                .long   SYMBOL_NAME(sys_getdents64)
+               .long   SYMBOL_NAME(sys_pivot_root)
+               .long   SYMBOL_NAME(sys_mincore)
+/* 220 */      .long   SYMBOL_NAME(sys_madvise)
+               .long   SYMBOL_NAME(sys_fcntl64)
+__syscall_end:
 
-               .rept   NR_syscalls-217
+               .rept   NR_syscalls - (__syscall_end - __syscall_start) / 4
                        .long   SYMBOL_NAME(sys_ni_syscall)
                .endr
 #endif
index 698783e5affa08f140f106a6a0f3ba663b79ea88..6070112547da76b7f805a4f8163a21001afe2dd5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/ecard.c
  *
- *  Copyright 1995-1998 Russell King
+ *  Copyright 1995-2001 Russell King
  *
  * 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
@@ -26,7 +26,6 @@
  *  17-Apr-1999        RMK     Support for EASI Type C cycles.
  */
 #define ECARD_C
-#define __KERNEL_SYSCALLS__
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -34,6 +33,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
@@ -382,12 +382,12 @@ ecard_call(struct ecard_request *req)
  * We ignore all calls, unless it is a SYS_RESTART call - power down/halts
  * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
  */
-static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
+static int ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
 {
        struct ecard_request req;
 
        if (val != SYS_RESTART)
-               return;
+               return 0;
 
        /*
         * Disable the expansion card interrupt
@@ -414,6 +414,7 @@ static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
        have_expmask = ~0;
        __raw_writeb(have_expmask, EXPMASK_ENABLE);
 #endif
+       return 0;
 }
 
 static struct notifier_block ecard_reboot_notifier = {
index 9f39d66e8f4acbdd679fb6212d277f517a38866e..5704560c5e7e12228ccdefab31f7c2ab68100339 100644 (file)
@@ -1179,7 +1179,6 @@ ENTRY(__trap_init)
                stmfd   sp!, {r4 - r6, lr}
 
                adr     r1, .LCvectors                  @ set up the vectors
-               mov     r0, #0
                ldmia   r1, {r1, r2, r3, r4, r5, r6, ip, lr}
                stmia   r0, {r1, r2, r3, r4, r5, r6, ip, lr}
 
index 2d7350664bf2c6ea140fb085cee1cfc1b0e23f80..e82fafb6a56e9995e5326437710b7a1327161367 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define FIQ_VECTOR 0x1c
+#define FIQ_VECTOR (vectors_base() + 0x1c)
 
 static unsigned long no_fiq_insn;
 
index 7cbec14062a1be99f152a7caad53ed4dcef9e6bf..453598e5ef0664c6854528517f2ff9eeb9ee3c69 100644 (file)
@@ -55,10 +55,19 @@ inline long do_mmap2(
        unsigned long prot, unsigned long flags,
        unsigned long fd, unsigned long pgoff)
 {
-       int error = -EBADF;
+       int error = -EINVAL;
        struct file * file = NULL;
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+       /*
+        * If we are doing a fixed mapping, and address < PAGE_SIZE,
+        * then deny it.
+        */
+       if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0)
+               goto out;
+
+       error = -EBADF;
        if (!(flags & MAP_ANONYMOUS)) {
                file = fget(fd);
                if (!file)
@@ -101,6 +110,29 @@ out:
        return error;
 }
 
+asmlinkage unsigned long
+sys_arm_mremap(unsigned long addr, unsigned long old_len,
+              unsigned long new_len, unsigned long flags,
+              unsigned long new_addr)
+{
+       unsigned long ret = -EINVAL;
+
+       /*
+        * If we are doing a fixed mapping, and address < PAGE_SIZE,
+        * then deny it.
+        */
+       if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE &&
+           vectors_base() == 0)
+               goto out;
+
+       down_write(&current->mm->mmap_sem);
+       ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+       up_write(&current->mm->mmap_sem);
+
+out:
+       return ret;
+}
+
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls.
index 8455caf784dddd5fe8967c352f6e34a9e26ec6cf..aad7efbf2790f679a24d05cafc261f6e49588e06 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/ptrace.h>
+#include <linux/elf.h>
 #include <linux/init.h>
 
 #include <asm/atomic.h>
@@ -27,6 +28,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #include "ptrace.h"
 
@@ -143,12 +145,24 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
                c_backtrace(fp, processor_mode(regs));
 }
 
+/*
+ * This is called from SysRq-T (show_task) to display the current
+ * call trace for each process.  Very useful.
+ */
+void show_trace_task(struct task_struct *tsk)
+{
+       if (tsk != current) {
+               unsigned int fp = tsk->thread.save->fp;
+               c_backtrace(fp, 0x10);
+       }
+}
+
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * This function is protected against re-entrancy.
  */
-void die(const char *str, struct pt_regs *regs, int err)
+NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
 {
        struct task_struct *tsk = current;
 
@@ -173,9 +187,9 @@ void die(const char *str, struct pt_regs *regs, int err)
                fs = get_fs();
                set_fs(KERNEL_DS);
 
-               dump_instr(regs);
                dump_stack(tsk, (unsigned long)(regs + 1));
                dump_backtrace(regs, tsk);
+               dump_instr(regs);
 
                set_fs(fs);
        }
@@ -448,9 +462,12 @@ void abort(void)
 
 void __init trap_init(void)
 {
-       extern void __trap_init(void);
+       extern void __trap_init(void *);
 
-       __trap_init();
+       __trap_init((void *)vectors_base());
+       if (vectors_base() != 0)
+               printk("Relocating machine vectors to 0x%08x\n",
+                       vectors_base());
 #ifdef CONFIG_CPU_32
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 #endif
index 6e54901d126a91153fd7dc896ed08f3c3d2628e5..384129705a9e3f9634a236bdde938e7e28620100 100644 (file)
@@ -1,10 +1,7 @@
 /*
  *  linux/arch/arm/mach-ebsa110/arch.c
  *
- *  Architecture specific fixups.  This is where any
- *  parameters in the params struct are fixed up, or
- *  any additional architecture specific information
- *  is pulled from the params struct.
+ *  Architecture specific fixups.
  */
 #include <linux/tty.h>
 #include <linux/delay.h>
diff --git a/arch/arm/mach-ebsa110/hardware.h b/arch/arm/mach-ebsa110/hardware.h
new file mode 100644 (file)
index 0000000..1f50392
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/hardware.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ *  Local hardware definitions.
+ */
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#define IRQ_MASK               0xfe000000      /* read */
+#define IRQ_MSET               0xfe000000      /* write */
+#define IRQ_STAT               0xff000000      /* read */
+#define IRQ_MCLR               0xff000000      /* write */
+
+#endif
index f8c6da36d257f959bddb95735eefe35e83e2b92c..0df56adbefbe38546173b74a6d90faa193826ae5 100644 (file)
@@ -188,6 +188,7 @@ u16 __inw(int port)
 u32 __inl(int port)
 {
        BUG();
+       return 0;
 }
 
 EXPORT_SYMBOL(__inb);
index efecca788ff760fb531237eaab6cb982f22ab7ed..8987918f6ef7de4d0d36a79a63e1d16a1f4ed098 100644 (file)
@@ -67,18 +67,21 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
 #endif
 
        /*
-        * free wasted pages.  We skip the first page since
-        * we know that it will have count = 1 and won't
-        * require freeing.
+        * free wasted pages.  We skip the first page since we know
+        * that it will have count = 1 and won't require freeing.
+        * We also mark the pages in use as reserved so that
+        * remap_page_range works.
         */
        page = virt_to_page(virt);
        free = page + (size >> PAGE_SHIFT);
        end  = page + (1 << order);
 
-       while (++page < end) {
+       for (; page < end; page++) {
                set_page_count(page, 1);
                if (page >= free)
                        __free_page(page);
+               else
+                       SetPageReserved(page);
        }
        return ret;
 
@@ -108,11 +111,27 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handl
  * free a page as defined by the above mapping.  We expressly forbid
  * calling this from interrupt context.
  */
-void consistent_free(void *vaddr)
+void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
 {
+       struct page *page, *end;
+       void *virt;
+
        if (in_interrupt())
                BUG();
 
+       virt = bus_to_virt(handle);
+
+       /*
+        * More messing around with the MM internals.  This is
+        * sick, but then so is remap_page_range().
+        */
+       size = PAGE_ALIGN(size);
+       page = virt_to_page(virt);
+       end = page + (size >> PAGE_SHIFT);
+
+       for (; page < end; page++)
+               ClearPageReserved(page);
+
        __iounmap(vaddr);
 }
 
index eee7ae1b0e0cca6fcdc58544096d980bc6283744..7649dbcfdefe09b72f6504417996df7e4a7dc3ba 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/unaligned.h>
 
@@ -45,9 +46,8 @@ extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
  *
  * Speed optimisations and better fault handling by Russell King.
  *
- * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet.  Also,
- * it seems to give a severe performance impact (1 abort/ms - NW runs at
- * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
+ * *** NOTE ***
+ * This code is not portable to processors with late data abort handling.
  */
 #define CODING_BITS(i) (i & 0x0e000000)
 
@@ -57,6 +57,8 @@ extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
 #define LDST_W_BIT(i)  (i & (1 << 21))         /* Writeback            */
 #define LDST_L_BIT(i)  (i & (1 << 20))         /* Load                 */
 
+#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
+
 #define LDSTH_I_BIT(i) (i & (1 << 22))         /* half-word immed      */
 #define LDM_S_BIT(i)   (i & (1 << 22))         /* write CPSR from SPSR */
 
@@ -336,29 +338,48 @@ fault:
        return TYPE_FAULT;
 }
 
+/*
+ * LDM/STM alignment handler.
+ *
+ * There are 4 variants of this instruction:
+ *
+ * B = rn pointer before instruction, A = rn pointer after instruction
+ *              ------ increasing address ----->
+ *             |    | r0 | r1 | ... | rx |    |
+ * PU = 01             B                    A
+ * PU = 11        B                    A
+ * PU = 00        A                    B
+ * PU = 10             A                    B
+ */
 static int
 do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
 {
        unsigned int rd, rn, correction, nr_regs, regbits;
-       unsigned long eaddr;
-
-       correction = 4; /* sometimes 8 on ARMv3 */
-       regs->ARM_pc += correction;
-
-       rd = RD_BITS(instr);
-       rn = RN_BITS(instr);
-       eaddr = regs->uregs[rn];
+       unsigned long eaddr, newaddr;
 
        if (LDM_S_BIT(instr))
                goto bad;
 
+       correction = 4; /* processor implementation defined */
+       regs->ARM_pc += correction;
+
        ai_multi += 1;
 
+       /* count the number of registers in the mask to be transferred */
        for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
                nr_regs += 4;
 
+       rn = RN_BITS(instr);
+       newaddr = eaddr = regs->uregs[rn];
+
+       if (!LDST_U_BIT(instr))
+               nr_regs = -nr_regs;
+       newaddr += nr_regs;
        if (!LDST_U_BIT(instr))
-               eaddr -= nr_regs;
+               eaddr = newaddr;
+
+       if (LDST_P_EQ_U(instr)) /* U = P */
+               eaddr += 4;
 
        /*
         * This is a "hint" - we already have eaddr worked out by the
@@ -369,34 +390,23 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
                        "addr = %08lx, eaddr = %08lx\n",
                         instruction_pointer(regs), instr, addr, eaddr);
 
-       if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
-           (LDST_U_BIT(instr)      && LDST_P_BIT(instr)))
-               eaddr += 4;
-
        for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
                if (regbits & 1) {
-                       if (LDST_L_BIT(instr)) {
+                       if (LDST_L_BIT(instr))
                                get32_unaligned_check(regs->uregs[rd], eaddr);
-                               if (rd == 15)
-                                       correction = 0;
-                       } else
+                       else
                                put32_unaligned_check(regs->uregs[rd], eaddr);
                        eaddr += 4;
                }
 
-       if (LDST_W_BIT(instr)) {
-               if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
-                       eaddr -= nr_regs;
-               else if (LDST_P_BIT(instr))
-                       eaddr -= 4;
-               else if (!LDST_U_BIT(instr))
-                       eaddr -= 4 + nr_regs;
-               regs->uregs[rn] = eaddr;
-       }
-       regs->ARM_pc -= correction;
+       if (LDST_W_BIT(instr))
+               regs->uregs[rn] = newaddr;
+       if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
+               regs->ARM_pc -= correction;
        return TYPE_DONE;
 
 fault:
+       regs->ARM_pc -= correction;
        return TYPE_FAULT;
 
 bad:
index 9c7f5b7b39d885fd38f170e406d26334f83d4be2..ba6133da78b0c48177262636412283a5a3bbe666 100644 (file)
@@ -79,37 +79,40 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
 
        memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 
-       /*
-        * This lock is here just to satisfy pmd_alloc and pte_lock
-        */
-       spin_lock(&mm->page_table_lock);
+       init_pgd = pgd_offset_k(0);
 
-       /*
-        * On ARM, first page must always be allocated since it contains
-        * the machine vectors.
-        */
-       new_pmd = pmd_alloc(mm, new_pgd, 0);
-       if (!new_pmd)
-               goto no_pmd;
+       if (vectors_base() == 0) {
+               init_pmd = pmd_offset(init_pgd, 0);
+               init_pte = pte_offset(init_pmd, 0);
 
-       new_pte = pte_alloc(mm, new_pmd, 0);
-       if (!new_pte)
-               goto no_pte;
+               /*
+                * This lock is here just to satisfy pmd_alloc and pte_lock
+                */
+               spin_lock(&mm->page_table_lock);
 
-       init_pgd = pgd_offset_k(0);
-       init_pmd = pmd_offset(init_pgd, 0);
-       init_pte = pte_offset(init_pmd, 0);
+               /*
+                * On ARM, first page must always be allocated since it
+                * contains the machine vectors.
+                */
+               new_pmd = pmd_alloc(mm, new_pgd, 0);
+               if (!new_pmd)
+                       goto no_pmd;
 
-       set_pte(new_pte, *init_pte);
+               new_pte = pte_alloc(mm, new_pmd, 0);
+               if (!new_pte)
+                       goto no_pte;
+
+               set_pte(new_pte, *init_pte);
+
+               spin_unlock(&mm->page_table_lock);
+       }
 
        /*
         * Copy over the kernel and IO PGD entries
         */
-       memcpy(new_pgd  + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+       memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
                       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
 
-       spin_unlock(&mm->page_table_lock);
-
        /*
         * FIXME: this should not be necessary
         */
@@ -134,25 +137,26 @@ no_pgd:
 
 void free_pgd_slow(pgd_t *pgd)
 {
-       if (pgd) { /* can pgd be NULL? */
-               pmd_t *pmd;
-               pte_t *pte;
-
-               /* pgd is always present and good */
-               pmd = (pmd_t *)pgd;
-               if (pmd_none(*pmd))
-                       goto free;
-               if (pmd_bad(*pmd)) {
-                       pmd_ERROR(*pmd);
-                       pmd_clear(pmd);
-                       goto free;
-               }
-
-               pte = pte_offset(pmd, 0);
+       pmd_t *pmd;
+       pte_t *pte;
+
+       if (!pgd)
+               return;
+
+       /* pgd is always present and good */
+       pmd = (pmd_t *)pgd;
+       if (pmd_none(*pmd))
+               goto free;
+       if (pmd_bad(*pmd)) {
+               pmd_ERROR(*pmd);
                pmd_clear(pmd);
-               pte_free(pte);
-               pmd_free(pmd);
+               goto free;
        }
+
+       pte = pte_offset(pmd, 0);
+       pmd_clear(pmd);
+       pte_free(pte);
+       pmd_free(pmd);
 free:
        free_pages((unsigned long) pgd, 2);
 }
@@ -296,17 +300,6 @@ void __init memtable_init(struct meminfo *mi)
 
        init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE);
 
-       p->physical   = virt_to_phys(init_maps);
-       p->virtual    = 0;
-       p->length     = PAGE_SIZE;
-       p->domain     = DOMAIN_USER;
-       p->prot_read  = 0;
-       p->prot_write = 0;
-       p->cacheable  = 1;
-       p->bufferable = 0;
-
-       p ++;
-
        for (i = 0; i < mi->nr_banks; i++) {
                if (mi->bank[i].size == 0)
                        continue;
@@ -349,17 +342,10 @@ void __init memtable_init(struct meminfo *mi)
        p ++;
 #endif
 
-       /*
-        * We may have a mapping in virtual address 0.
-        * Clear it out.
-        */
-       clear_mapping(0);
-
        /*
         * Go through the initial mappings, but clear out any
         * pgdir entries that are not in the description.
         */
-       i = 0;
        q = init_maps;
        do {
                if (address < q->virtual || q == p) {
@@ -375,6 +361,21 @@ void __init memtable_init(struct meminfo *mi)
                }
        } while (address != 0);
 
+       /*
+        * Create a mapping for the machine vectors at virtual address 0
+        * or 0xffff0000.  We should always try the high mapping.
+        */
+       init_maps->physical   = virt_to_phys(init_maps);
+       init_maps->virtual    = vectors_base();
+       init_maps->length     = PAGE_SIZE;
+       init_maps->domain     = DOMAIN_USER;
+       init_maps->prot_read  = 0;
+       init_maps->prot_write = 0;
+       init_maps->cacheable  = 1;
+       init_maps->bufferable = 0;
+
+       create_mapping(init_maps);
+
        flush_cache_all();
 }
 
index bff00a65882fefa319762dfe73f4032e56f6ff30..1902d23fe39ebe23dd857f5b5976cbfdb20ff1c7 100644 (file)
@@ -10,7 +10,6 @@
 #include <asm/hardware.h>
 #include <asm/page.h>
 #include <asm/proc/domain.h>
-#include <asm/setup.h>
 
 #include <asm/mach/map.h>
 
index 698083c67b695dca022af9db4e4b3d9b0497e50c..0e5b1a227b2ecac34612d4a46f8f4c4b4c87512a 100644 (file)
@@ -16,7 +16,7 @@ $(TOPDIR)/include/asm-arm/mach-types.h: mach-types gen-mach-types
 
 $(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c
        $(CC) $(CFLAGS) -S -o - getconstants.c | \
-        sed 's/^\(#define .* \)#\(.*\)/\1\2/;/^#define/!d' | \
+        sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' | \
         cat constants-hdr - > $@.tmp
        cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@; $(RM) $@.tmp
 
index bad2ade80c63bb1902d4b458316396928d43bdf6..15c762f5371d26e15f30edd718299ccf9e8bbb97 100644 (file)
@@ -60,7 +60,5 @@ DEFN("PAGE_CLEAN",            _PAGE_CLEAN);
 
 DEFN("PAGE_SZ",                        PAGE_SIZE);
 
-DEFN("KSWI_BASE",              0x900000);
-DEFN("KSWI_SYS_BASE",          0x9f0000);
 DEFN("SYS_ERROR0",             0x9f0000);
 }
index 61783c1553b7b3343b269a55b9554a1b19f887e3..0bd20fe44e12f6f31b8dad80a3b5873814af0cb1 100644 (file)
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Sat Apr 7 09:45:09 2001
+# Last update: Sun Jun 17 00:53:17 2001
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -63,7 +63,7 @@ edb7211                       ARCH_EDB7211            EDB7211                 50
 citygo                 SA1100_CITYGO           CITYGO                  51
 pfs168                 SA1100_PFS168           PFS168                  52
 spot                   SA1100_SPOT             SPOT                    53
-flexanet               ARCH_FLEXANET           FLEXANET                54
+flexanet               SA1100_FLEXANET         FLEXANET                54
 webpal                 ARCH_WEBPAL             WEBPAL                  55
 linpda                 SA1100_LINPDA           LINPDA                  56
 anakin                 ARCH_ANAKIN             ANAKIN                  57
@@ -77,6 +77,26 @@ psion_series7                SA1100_PSION_SERIES7    PSION_SERIES7           64
 xfile                  SA1100_XFILE            XFILE                   65
 accelent_ep9312                ARCH_ACCELENT_EP9312    ACCELENT_EP9312         66
 ic200                  ARCH_IC200              IC200                   67
+creditlart             SA1100_CREDITLART       CREDITLART              68
+htm                    SA1100_HTM              HTM                     69
+iq80310                        ARCH_IQ80310            IQ80310                 70
+freebot                        SA1100_FREEBOT          FREEBOT                 71
+entel                  ARCH_ENTEL              ENTEL                   72
+enp3510                        ARCH_ENP3510            ENP3510                 73
+trizeps                        SA1100_TRIZEPS          TRIZEPS                 74
+nesa                   SA1100_NESA             NESA                    75
+venus                  ARCH_VENUS              VENUS                   76
+tardis                 ARCH_TARDIS             TARDIS                  77
+mercury                        ARCH_MERCURY            MERCURY                 78
+empeg                  SA1100_EMPEG            EMPEG                   79
+adi_eb                 ARCH_I80200FCC          I80200FCC               80
+itt_cpb                        SA1100_ITT_CPB          ITT_CPB                 81
+sa1110_svc             ARCH_SA1110_SVC         SA1110_SVC              82
+alpha2                 SA1100_ALPHA2           ALPHA2                  84
+alpha1                 SA1100_ALPHA1           ALPHA1                  85
+netarm                 ARCH_NETARM             NETARM                  86
+simpad                 SA1100_SIMPAD           SIMPAD                  87
+pda1                   ARCH_PDA1               PDA1                    88
+lubbock                        ARCH_LUBBOCK            LUBBOCK                 89
 
 # The following are unallocated
-empeg                  SA1100_EMPEG            EMPEG
index bcb627f15ec68f75567341c732722feb48630f49..35de35646dd7f16d0978bdd7ce9e808c94c74f3e 100644 (file)
@@ -102,64 +102,6 @@ CONFIG_PM=y
 #
 # CONFIG_MTD is not set
 
-#
-# RAM/ROM/Flash chip drivers
-#
-# CONFIG_MTD_CFI is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_JEDEC is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
-# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_OCELOT is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_SPIA is not set
-
 #
 # Parallel port support
 #
@@ -421,6 +363,13 @@ CONFIG_DUMMY=m
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -439,7 +388,6 @@ CONFIG_NET_PCI=y
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PM is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -456,16 +404,18 @@ CONFIG_EEPRO100=y
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_WINBOND_840 is not set
-# CONFIG_HAPPYMEAL is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
+# CONFIG_MYRI_SBUS is not set
 # CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
+# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -761,6 +711,7 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_IBMCAM is not set
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
 # CONFIG_USB_DSBR is not set
 # CONFIG_USB_DABUSB is not set
 
@@ -769,6 +720,7 @@ CONFIG_USB_STORAGE=y
 #
 # CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_CATC is not set
 # CONFIG_USB_NET1080 is not set
 
 #
index dc80b1dd5bb6855a02cde115d67cd8c9b2a398bd..48dd60f4cb4a5df788fa2acfac61ed0d935745ea 100644 (file)
@@ -182,7 +182,7 @@ void __init intel_mcheck_init(struct cpuinfo_x86 *c)
  *     Set up machine check reporting on the Winchip C6 series
  */
  
-static void winchip_mcheck_init(struct cpuinfo_x86 *c)
+static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 lo, hi;
        /* Not supported on C3 */
@@ -207,8 +207,14 @@ static void winchip_mcheck_init(struct cpuinfo_x86 *c)
  *     This has to be run for each processor
  */
 
+
+static int mce_disabled = 0;
+
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
+       if(mce_disabled)
+               return;
+               
        switch(c->x86_vendor)
        {
                case X86_VENDOR_AMD:
@@ -226,3 +232,9 @@ void __init mcheck_init(struct cpuinfo_x86 *c)
                        break;
        }
 }
+
+static void __init mcheck_disable(char *str, int *unused)
+{
+       mce_disabled = 1;
+}
+__setup("nomce", mcheck_disable);
index 6bd49fc73a9701e4304a14f7f24bf1d330d90988..934b283b4a725211f1e1d7bb275137b9dbad9e71 100644 (file)
@@ -29,7 +29,9 @@ comment 'Processor type and features'
 choice 'SuperH system type'                                    \
        "Generic                CONFIG_SH_GENERIC               \
         SolutionEngine         CONFIG_SH_SOLUTION_ENGINE       \
-        Overdrive              CONFIG_SH_OVERDRIVE             \
+        SolutionEngine7751     CONFIG_SH_7751_SOLUTION_ENGINE  \
+        STB1_Harp              CONFIG_SH_STB1_HARP             \
+        STB1_Overdrive         CONFIG_SH_STB1_OVERDRIVE        \
         HP620                  CONFIG_SH_HP620                 \
         HP680                  CONFIG_SH_HP680                 \
         HP690                  CONFIG_SH_HP690                 \
@@ -37,9 +39,17 @@ choice 'SuperH system type'                                  \
         DMIDA                  CONFIG_SH_DMIDA                 \
         EC3104                 CONFIG_SH_EC3104                \
         Dreamcast              CONFIG_SH_DREAMCAST             \
+        CAT68701               CONFIG_SH_CAT68701              \
+        BigSur                 CONFIG_SH_BIGSUR                \
+        SH2000                 CONFIG_SH_SH2000                \
         BareCPU                CONFIG_SH_UNKNOWN" Generic
 
-define_bool CONFIG_SH_RTC y
+# The SH7750 RTC module is disabled in the Dreamcast
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+   define_bool CONFIG_SH_RTC n
+else
+   define_bool CONFIG_SH_RTC y
+fi
 
 if [ "$CONFIG_SH_HP620" = "y" -o "$CONFIG_SH_HP680" = "y" -o \
      "$CONFIG_SH_HP690" = "y" ]; then
@@ -50,7 +60,9 @@ choice 'Processor type' \
    "SH7707 CONFIG_CPU_SUBTYPE_SH7707 \
     SH7708 CONFIG_CPU_SUBTYPE_SH7708 \
     SH7709 CONFIG_CPU_SUBTYPE_SH7709 \
-    SH7750 CONFIG_CPU_SUBTYPE_SH7750" SH7708
+    SH7750 CONFIG_CPU_SUBTYPE_SH7750 \
+    SH7751 CONFIG_CPU_SUBTYPE_SH7751 \
+    ST40STB1 CONFIG_CPU_SUBTYPE_ST40STB1" SH7708
 if [ "$CONFIG_CPU_SUBTYPE_SH7707" = "y" ]; then
    define_bool CONFIG_CPU_SH3 y
    define_bool CONFIG_CPU_SH4 n
@@ -67,12 +79,30 @@ if [ "$CONFIG_CPU_SUBTYPE_SH7750" = "y" ]; then
    define_bool CONFIG_CPU_SH3 n
    define_bool CONFIG_CPU_SH4 y
 fi
+if [ "$CONFIG_CPU_SUBTYPE_SH7751" = "y" ]; then
+   define_bool CONFIG_CPU_SH3 n
+   define_bool CONFIG_CPU_SH4 y
+fi
+if [ "$CONFIG_CPU_SUBTYPE_ST40STB1" = "y" ]; then
+   define_bool CONFIG_CPU_SH3 n
+   define_bool CONFIG_CPU_SH4 y
+fi
 bool 'Little Endian' CONFIG_CPU_LITTLE_ENDIAN
 if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_HP600" = "y" -o \
-     "$CONFIG_SH_OVERDRIVE" = "y" ]; then
+     "$CONFIG_SH_BIGSUR" = "y" -o "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+     "$CONFIG_SH_DREAMCAST" = "y" -o "$CONFIG_SH_SH2000" = "y" ]; then
   define_hex CONFIG_MEMORY_START 0c000000
 else
-  hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+  if [ "$CONFIG_CPU_SUBTYPE_ST40STB1" = "y" ]; then
+    bool 'Memory on LMI' CONFIG_ST40_LMI_MEMORY
+    if [ "$CONFIG_ST40_LMI_MEMORY" = "y" ] ; then
+      define_hex CONFIG_MEMORY_START 08000000
+    else
+      hex 'EMI physical memory start address' CONFIG_MEMORY_START 08000000
+    fi
+  else
+    hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+  fi
 fi
 endmenu
 
@@ -89,7 +119,8 @@ define_bool CONFIG_SBUS n
 
 bool 'Networking support' CONFIG_NET
 
-if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_UNKNOWN" = "y" ]; then
+if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o \
+     "$CONFIG_SH_UNKNOWN" = "y" -o "$CONFIG_SH_CAT68701" = "y" ]; then
   bool 'Compact Flash Enabler support' CONFIG_CF_ENABLER
 fi
 
@@ -101,6 +132,7 @@ fi
 
 bool 'Hitachi HD64465 companion chip support' CONFIG_HD64465
 if [ "$CONFIG_HD64465" = "y" ]; then
+   hex 'HD64465 start address' CONFIG_HD64465_IOBASE b0000000
    int 'HD64465 IRQ' CONFIG_HD64465_IRQ 5
 fi
 
@@ -197,6 +229,10 @@ fi
 #
 source drivers/input/Config.in
 
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+source drivers/maple/Config.in
+fi
+
 mainmenu_option next_comment
 comment 'Character devices'
 
@@ -217,10 +253,29 @@ if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
 fi
 
 if [ "$CONFIG_SH_GENERIC" = "y" -o \
-     "$CONFIG_SH_OVERDRIVE" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
+     "$CONFIG_SH_CAT68701" = "y" -o \
+     "$CONFIG_SH_STB1_HARP" = "y" -o \
+     "$CONFIG_SH_STB1_OVERDRIVE" = "y" -o \
+     "$CONFIG_SH_BIGSUR" = "y" -o \
+     "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+     "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
   bool 'Heartbeat LED' CONFIG_HEARTBEAT
 fi
 
+if [ "$CONFIG_SH_DREAMCAST" = "y" -a "$CONFIG_MAPLE" != "n" ]; then
+   mainmenu_option next_comment
+   comment 'Maple Bus input peripherals'
+   if [ "$CONFIG_INPUT" != "n" ]; then
+      dep_tristate '  Maple Bus keyboard support' CONFIG_MAPLE_KEYBOARD $CONFIG_INPUT
+      dep_tristate '  Maple Bus mouse support' CONFIG_MAPLE_MOUSE $CONFIG_INPUT
+   else
+      comment 'Input core support is required for Maple input peripherals'
+   fi
+   endmenu
+fi
+
+source drivers/char/joystick/Config.in
+
 if [ "$CONFIG_PARPORT" != "n" ]; then
    dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
    if [ "$CONFIG_PRINTER" != "n" ]; then
@@ -228,14 +283,17 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
-endmenu
-
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
 fi
+endmenu
 
 source fs/Config.in
 
+source drivers/media/Config.in
+
 if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
    comment 'Console drivers'
index d8dfe36e765053b50238ac9d9c53745bd4364acc..489a6995594565c9455ecfd2f00af073fb48b28e 100644 (file)
@@ -24,8 +24,15 @@ obj-$(CONFIG_SH_RTC)            += rtc.o
 obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
 
 ifeq ($(CONFIG_PCI),y)
-obj-y                          += pci-sh.o 
+ifeq ($(CONFIG_SH_DREAMCAST),y)
+obj-y                          += pci-dc.o
+else
+obj-y                           += pci-dma.o 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751)+= pci-sh7751.o 
+obj-$(CONFIG_SH_BIGSUR)+= pci-bigsur.o
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= pci-7751se.o
+endif
 endif
 
 obj-$(CONFIG_SH_HP600)         += mach_hp600.o
@@ -34,6 +41,15 @@ machine-specific-objs                += mach_hp600.o
 obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o
 machine-specific-objs          += mach_se.o setup_se.o io_se.o led_se.o
 
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o pci-7751se.o
+machine-specific-objs           += mach_se.o setup_se.o io_se.o led_se.o pci-7751se.o
+
+obj-$(CONFIG_SH_BIGSUR)                += mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
+machine-specific-objs          += mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
+
+obj-$(CONFIG_SH_SH2000)                += setup_sh2000.o io_sh2000.o
+machine-specific-objs          += setup_sh2000.o io_sh2000.o
+
 obj-$(CONFIG_SH_CAT68701)      += mach_cat68701.o io_cat68701.o
 machine-specific-objs          += mach_cat68701.o io_cat68701.o
 
index 196d0b17b445452ed2dffbd88502f84195e6884a..c854995615f5eb1d2e09cf6db8236b7c7b464a85 100644 (file)
@@ -489,8 +489,9 @@ __sct:      .long   SYMBOL_NAME(sys_call_table)
 __syscall_ret_trace:
        .long   syscall_ret_trace
 __syscall_ret:
-       .long   SYMBOL_NAME(syscall_ret)
-
+       .long   syscall_ret
+__INV_IMASK:
+       .long   0xffffff0f      ! ~(IMASK)
 
 
        .align  2
@@ -502,30 +503,16 @@ reschedule:
        .align  2
 1:     .long   SYMBOL_NAME(schedule)
 
-ENTRY(ret_from_irq)
+ret_from_irq:
+ret_from_exception:
        mov     #OFF_SR, r0
        mov.l   @(r0,r15), r0   ! get status register
        shll    r0
        shll    r0              ! kernel space?
        bt      restore_all     ! Yes, it's from kernel, go back soon
        !
-       STI()
-       bra     ret_with_reschedule
-        nop
-
-ENTRY(ret_from_exception)
-       mov     #OFF_SR, r0
-       mov.l   @(r0,r15), r0   ! get status register
-       shll    r0
-       shll    r0              ! kernel space?
-       bt      restore_all     ! Yes, it's from kernel, go back soon
-       !
-       STI()
        bra     ret_from_syscall
         nop
-       .align  2
-__INV_IMASK:
-       .long   0xffffff0f      ! ~(IMASK)
 
        .align 2
 #ifdef COMPAT_OLD_SYSCALL_ABI
@@ -538,16 +525,11 @@ syscall_ret:
        /* fall through */
 
 ENTRY(ret_from_syscall)
-       mov.l   __irq_stat, r0  ! softirq_active
-       mov.l   @r0, r1
-       mov.l   @(4,r0), r2     ! softirq_mask
-       tst     r2, r1
-       bt      ret_with_reschedule
-handle_softirq:
-       mov.l   __do_softirq, r0
-       jsr     @r0
-        nop
-ret_with_reschedule:
+       /* CLI */
+       stc     sr, r0
+       or      #0xf0, r0
+       ldc     r0, sr
+       !
        stc     k_current, r1
        mov.l   @(need_resched,r1), r0
        tst     r0, r0
@@ -567,8 +549,6 @@ __do_signal:
        .long   SYMBOL_NAME(do_signal)
 __irq_stat:
        .long   SYMBOL_NAME(irq_stat)
-__do_softirq:
-       .long   SYMBOL_NAME(do_softirq)
 
        .align 2
 restore_all:
@@ -707,7 +687,7 @@ general_exception:
        bra     handle_exception
         mov.l  @k2, k2
        .align  2
-2:     .long   SYMBOL_NAME(ret_from_exception)
+2:     .long   ret_from_exception
 1:     .long   EXPEVT
 !
 !
@@ -728,8 +708,8 @@ interrupt:
        .align  2
 1:     .long   EXPEVT
 2:     .long   INTEVT
-3:     .long   SYMBOL_NAME(ret_from_irq)
-4:     .long   SYMBOL_NAME(ret_from_exception)
+3:     .long   ret_from_irq
+4:     .long   ret_from_exception
 
 !
 !
@@ -941,24 +921,143 @@ ENTRY(interrupt_table)
        .long   SYMBOL_NAME(do_IRQ)     ! 63      pcc1i
 #endif
 #elif defined(__SH4__)
-       .long   SYMBOL_NAME(do_IRQ)     ! Hitachi UDI
-       .long   SYMBOL_NAME(do_IRQ)     ! GPIO
-       .long   SYMBOL_NAME(do_IRQ)     ! DMAC dmte0
-       .long   SYMBOL_NAME(do_IRQ)     !      dmte1
-       .long   SYMBOL_NAME(do_IRQ)     !      dmte2
-       .long   SYMBOL_NAME(do_IRQ)     !      dmte3
-       .long   SYMBOL_NAME(do_IRQ)     !      dmae
-       .long   SYMBOL_NAME(do_IRQ)
-       .long   SYMBOL_NAME(do_IRQ)     ! SCIF eri
-       .long   SYMBOL_NAME(do_IRQ)     !      rxi
-       .long   SYMBOL_NAME(do_IRQ)     !      bri
-       .long   SYMBOL_NAME(do_IRQ)     !      txi
+       .long   SYMBOL_NAME(do_IRQ)     ! 32 Hitachi UDI
+       .long   SYMBOL_NAME(do_IRQ)     ! 33 GPIO
+       .long   SYMBOL_NAME(do_IRQ)     ! 34 DMAC dmte0
+       .long   SYMBOL_NAME(do_IRQ)     ! 35      dmte1
+       .long   SYMBOL_NAME(do_IRQ)     ! 36      dmte2
+       .long   SYMBOL_NAME(do_IRQ)     ! 37      dmte3
+       .long   SYMBOL_NAME(do_IRQ)     ! 38      dmae
+       .long   error                   ! 39
+       .long   SYMBOL_NAME(do_IRQ)     ! 40 SCIF eri
+       .long   SYMBOL_NAME(do_IRQ)     ! 41      rxi
+       .long   SYMBOL_NAME(do_IRQ)     ! 42      bri
+       .long   SYMBOL_NAME(do_IRQ)     ! 43      txi
+       .long   error                   ! 44
+       .long   error                   ! 45
+       .long   error                   ! 46
+       .long   error                   ! 47
+       .long   SYMBOL_NAME(do_fpu_state_restore)       ! 48
+       .long   SYMBOL_NAME(do_fpu_state_restore)       ! 49
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+       .long   error
+       .long   error
+       .long   error
+       .long   error
+       .long   error
+       .long   error
+       .long   error
+       .long   error
+       .long   error
+       .long   error
        .long   error
        .long   error
        .long   error
        .long   error
-       .long   SYMBOL_NAME(do_fpu_state_restore)
-       .long   SYMBOL_NAME(do_fpu_state_restore)
+       .long   SYMBOL_NAME(do_IRQ)     ! PCI serr
+       .long   SYMBOL_NAME(do_IRQ)     !     dma3
+       .long   SYMBOL_NAME(do_IRQ)     !     dma2
+       .long   SYMBOL_NAME(do_IRQ)     !     dma1
+       .long   SYMBOL_NAME(do_IRQ)     !     dma0
+       .long   SYMBOL_NAME(do_IRQ)     !     pwon
+       .long   SYMBOL_NAME(do_IRQ)     !     pwdwn
+       .long   SYMBOL_NAME(do_IRQ)     !     err
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+       .long   error                   !  50 0x840
+       .long   error                   !  51 0x860
+       .long   error                   !  52 0x880
+       .long   error                   !  53 0x8a0
+       .long   error                   !  54 0x8c0
+       .long   error                   !  55 0x8e0
+       .long   error                   !  56 0x900
+       .long   error                   !  57 0x920
+       .long   error                   !  58 0x940
+       .long   error                   !  59 0x960
+       .long   error                   !  60 0x980
+       .long   error                   !  61 0x9a0
+       .long   error                   !  62 0x9c0
+       .long   error                   !  63 0x9e0
+       .long   SYMBOL_NAME(do_IRQ)     !  64 0xa00 PCI serr
+       .long   SYMBOL_NAME(do_IRQ)     !  65 0xa20     err
+       .long   SYMBOL_NAME(do_IRQ)     !  66 0xa40     ad
+       .long   SYMBOL_NAME(do_IRQ)     !  67 0xa60     pwr_dwn
+       .long   error                   !  68 0xa80
+       .long   error                   !  69 0xaa0
+       .long   error                   !  70 0xac0
+       .long   error                   !  71 0xae0
+       .long   SYMBOL_NAME(do_IRQ)     !  72 0xb00 DMA INT0
+       .long   SYMBOL_NAME(do_IRQ)     !  73 0xb20     INT1
+       .long   SYMBOL_NAME(do_IRQ)     !  74 0xb40     INT2
+       .long   SYMBOL_NAME(do_IRQ)     !  75 0xb60     INT3
+       .long   SYMBOL_NAME(do_IRQ)     !  76 0xb80     INT4
+       .long   error                   !  77 0xba0
+       .long   SYMBOL_NAME(do_IRQ)     !  78 0xbc0 DMA ERR
+       .long   error                   !  79 0xbe0
+       .long   SYMBOL_NAME(do_IRQ)     !  80 0xc00 PIO0
+       .long   SYMBOL_NAME(do_IRQ)     !  81 0xc20 PIO1
+       .long   SYMBOL_NAME(do_IRQ)     !  82 0xc40 PIO2
+       .long   error                   !  83 0xc60
+       .long   error                   !  84 0xc80
+       .long   error                   !  85 0xca0
+       .long   error                   !  86 0xcc0
+       .long   error                   !  87 0xce0
+       .long   error                   !  88 0xd00
+       .long   error                   !  89 0xd20
+       .long   error                   !  90 0xd40
+       .long   error                   !  91 0xd60
+       .long   error                   !  92 0xd80
+       .long   error                   !  93 0xda0
+       .long   error                   !  94 0xdc0
+       .long   error                   !  95 0xde0
+       .long   error                   !  96 0xe00
+       .long   error                   !  97 0xe20
+       .long   error                   !  98 0xe40
+       .long   error                   !  99 0xe60
+       .long   error                   ! 100 0xe80
+       .long   error                   ! 101 0xea0
+       .long   error                   ! 102 0xec0
+       .long   error                   ! 103 0xee0
+       .long   error                   ! 104 0xf00
+       .long   error                   ! 105 0xf20
+       .long   error                   ! 106 0xf40
+       .long   error                   ! 107 0xf60
+       .long   error                   ! 108 0xf80
+       .long   error                   ! 109 0xfa0
+       .long   error                   ! 110 0xfc0
+       .long   error                   ! 111 0xfe0
+       .long   SYMBOL_NAME(do_IRQ)     ! 112 0x1000 Mailbox
+       .long   error                   ! 113 0x1020
+       .long   error                   ! 114 0x1040
+       .long   error                   ! 115 0x1060
+       .long   error                   ! 116 0x1080
+       .long   error                   ! 117 0x10a0
+       .long   error                   ! 118 0x10c0
+       .long   error                   ! 119 0x10e0
+       .long   error                   ! 120 0x1100
+       .long   error                   ! 121 0x1120
+       .long   error                   ! 122 0x1140
+       .long   error                   ! 123 0x1160
+       .long   error                   ! 124 0x1180
+       .long   error                   ! 125 0x11a0
+       .long   error                   ! 126 0x11c0
+       .long   error                   ! 127 0x11e0
+       .long   error                   ! 128 0x1200
+       .long   error                   ! 129 0x1220
+       .long   error                   ! 130 0x1240
+       .long   error                   ! 131 0x1260
+       .long   error                   ! 132 0x1280
+       .long   error                   ! 133 0x12a0
+       .long   error                   ! 134 0x12c0
+       .long   error                   ! 135 0x12e0
+       .long   error                   ! 136 0x1300
+       .long   error                   ! 137 0x1320
+       .long   error                   ! 138 0x1340
+       .long   error                   ! 139 0x1360
+       .long   SYMBOL_NAME(do_IRQ)     ! 140 0x1380 EMPI INV_ADDR
+       .long   error                   ! 141 0x13a0
+       .long   error                   ! 142 0x13c0
+       .long   error                   ! 143 0x13e0
 #endif
 
 ENTRY(sys_call_table)
index d35d42c6761e6c6e72dcf69094b5d1ff216729e2..6b9e511dd14324cb4115703ef00b9179e7190d37 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: hd64465_gpio.c,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * $Id: hd64465_gpio.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
  * by Greg Banks <gbanks@pocketpenguins.com>
  * (c) 2000 PocketPenguins Inc
  *
diff --git a/arch/sh/kernel/io_bigsur.c b/arch/sh/kernel/io_bigsur.c
new file mode 100644 (file)
index 0000000..15a6f3a
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * include/asm-sh/io_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc. 
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/bigsur.h>
+
+//#define BIGSUR_DEBUG 2
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...)       printk(args)
+#define DIPRINTK(n, args...)   if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif
+
+
+/* Low iomap maps port 0-1K to addresses in 8byte chunks */
+#define BIGSUR_IOMAP_LO_THRESH 0x400
+#define BIGSUR_IOMAP_LO_SHIFT  3
+#define BIGSUR_IOMAP_LO_MASK   ((1<<BIGSUR_IOMAP_LO_SHIFT)-1)
+#define BIGSUR_IOMAP_LO_NMAP   (BIGSUR_IOMAP_LO_THRESH>>BIGSUR_IOMAP_LO_SHIFT)
+static u32 bigsur_iomap_lo[BIGSUR_IOMAP_LO_NMAP];
+static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP];
+
+/* High iomap maps port 1K-64K to addresses in 1K chunks */
+#define BIGSUR_IOMAP_HI_THRESH 0x10000
+#define BIGSUR_IOMAP_HI_SHIFT  10
+#define BIGSUR_IOMAP_HI_MASK   ((1<<BIGSUR_IOMAP_HI_SHIFT)-1)
+#define BIGSUR_IOMAP_HI_NMAP   (BIGSUR_IOMAP_HI_THRESH>>BIGSUR_IOMAP_HI_SHIFT)
+static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP];
+static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP];
+
+#ifndef MAX
+#define MAX(a,b)    ((a)>(b)?(a):(b))
+#endif
+
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
+void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift)
+{
+    u32 port, endport = baseport + nports;
+
+    DPRINTK("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n",
+           baseport, nports, addr);
+           
+       for (port = baseport ;
+            port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+            port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+               DPRINTK("    maplo[0x%x] = 0x%08x\n", port, addr);
+           bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = addr;
+           bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift;
+               addr += (1<<(BIGSUR_IOMAP_LO_SHIFT));
+       }
+
+       for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+            port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+            port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+               DPRINTK("    maphi[0x%x] = 0x%08x\n", port, addr);
+           bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = addr;
+           bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift;
+               addr += (1<<(BIGSUR_IOMAP_HI_SHIFT));
+       }
+}
+EXPORT_SYMBOL(bigsur_port_map);
+
+void bigsur_port_unmap(u32 baseport, u32 nports)
+{
+    u32 port, endport = baseport + nports;
+       
+    DPRINTK("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports);
+
+       for (port = baseport ;
+            port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+            port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+           bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0;
+       }
+
+       for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+            port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+            port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+           bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0;
+       }
+}
+EXPORT_SYMBOL(bigsur_port_unmap);
+
+unsigned long bigsur_isa_port2addr(unsigned long port)
+{
+    unsigned long addr = 0;
+       unsigned char shift;
+
+       /* Physical address not in P0, do nothing */
+       if (PXSEG(port)) addr = port;
+       /* physical address in P0, map to P2 */
+       else if (port >= 0x30000)
+           addr = P2SEGADDR(port);
+       /* Big Sur I/O + HD64465 registers 0x10000-0x30000 */
+       else if (port >= BIGSUR_IOMAP_HI_THRESH)
+           addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH);
+       /* Handle remapping of high IO/PCI IO ports */
+       else if (port >= BIGSUR_IOMAP_LO_THRESH) {
+           addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT];
+           shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT];
+           if (addr != 0)
+                   addr += (port & BIGSUR_IOMAP_HI_MASK) << shift;
+       }
+       /* Handle remapping of low IO ports */
+       else {
+           addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT];
+           shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT];
+           if (addr != 0)
+               addr += (port & BIGSUR_IOMAP_LO_MASK) << shift;
+       }
+
+    DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr);
+
+       return addr;
+}
+
+static inline void delay(void)
+{
+       ctrl_inw(0xa0000000);
+}
+
+unsigned char bigsur_inb(unsigned long port)
+{
+       unsigned long addr = PORT2ADDR(port);
+       unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+
+       DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b);
+       return b;
+}
+
+unsigned char bigsur_inb_p(unsigned long port)
+{
+    unsigned long v;
+       unsigned long addr = PORT2ADDR(port);
+
+       v = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+       delay();
+       DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v);
+       return v;
+}
+
+unsigned short bigsur_inw(unsigned long port)
+{
+    unsigned long addr = PORT2ADDR(port);
+       unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr);
+       DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b);
+       return b;
+}
+
+unsigned int bigsur_inl(unsigned long port)
+{
+    unsigned long addr = PORT2ADDR(port);
+       unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr);
+       DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b);
+       return b;
+}
+
+void bigsur_insb(unsigned long port, void *buffer, unsigned long count)
+{
+       unsigned char *buf=buffer;
+       while(count--) *buf++=inb(port);
+}
+
+void bigsur_insw(unsigned long port, void *buffer, unsigned long count)
+{
+       unsigned short *buf=buffer;
+       while(count--) *buf++=inw(port);
+}
+
+void bigsur_insl(unsigned long port, void *buffer, unsigned long count)
+{
+       unsigned long *buf=buffer;
+       while(count--) *buf++=inl(port);
+}
+
+void bigsur_outb(unsigned char b, unsigned long port)
+{
+       unsigned long addr = PORT2ADDR(port);
+
+       DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr);
+       if (addr != 0)
+           *(volatile unsigned char*)addr = b;
+}
+
+void bigsur_outb_p(unsigned char b, unsigned long port)
+{
+       unsigned long addr = PORT2ADDR(port);
+
+       DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr);
+    if (addr != 0)
+           *(volatile unsigned char*)addr = b;
+       delay();
+}
+
+void bigsur_outw(unsigned short b, unsigned long port)
+{
+       unsigned long addr = PORT2ADDR(port);
+       DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr);
+       if (addr != 0)
+           *(volatile unsigned short*)addr = b;
+}
+
+void bigsur_outl(unsigned int b, unsigned long port)
+{
+       unsigned long addr = PORT2ADDR(port);
+       DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr);
+       if (addr != 0)
+            *(volatile unsigned long*)addr = b;
+}
+
+void bigsur_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+       const unsigned char *buf=buffer;
+       while(count--) outb(*buf++, port);
+}
+
+void bigsur_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+       const unsigned short *buf=buffer;
+       while(count--) outw(*buf++, port);
+}
+
+void bigsur_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+       const unsigned long *buf=buffer;
+       while(count--) outl(*buf++, port);
+}
+
index a047d58c3e25a08c716fd826c72ff45852d796d9..9d27dc938ada88af148f01ef2c18c88b93262324 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: io_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *     $Id: io_dc.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
  *     I/O routines for SEGA Dreamcast
  */
 
index bd090f59460ca8f294ae2e07b83542769917463f..3944a73b2979c4176f35bcc248c9925940299f09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: io_hd64465.c,v 1.6 2001/02/15 09:13:51 dave_mckay Exp $
+ * $Id: io_hd64465.c,v 1.7 2001/05/09 07:39:36 gniibe Exp $
  * by Greg Banks <gbanks@pocketpenguins.com>
  * (c) 2000 PocketPenguins Inc
  *
@@ -52,6 +52,8 @@ static unsigned char  hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP];
 #define MAX(a,b)    ((a)>(b)?(a):(b))
 #endif
 
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
 void hd64465_port_map(unsigned short baseport, unsigned int nports,
                      unsigned long addr, unsigned char shift)
 {
@@ -101,7 +103,7 @@ void hd64465_port_unmap(unsigned short baseport, unsigned int nports)
 }
 EXPORT_SYMBOL(hd64465_port_unmap);
 
-static /*__inline__*/ unsigned long PORT2ADDR(unsigned long port)
+unsigned long hd64465_isa_port2addr(unsigned long port)
 {
        unsigned long addr = 0;
        unsigned char shift;
diff --git a/arch/sh/kernel/io_sh2000.c b/arch/sh/kernel/io_sh2000.c
new file mode 100644 (file)
index 0000000..f830675
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * I/O routine for SH-2000
+ */
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+#define IDE_OFFSET    0xb6200000
+#define NIC_OFFSET    0xb6000000
+#define EXTBUS_OFFSET 0xba000000
+
+unsigned long sh2000_isa_port2addr(unsigned long offset)
+{
+       if((offset & ~7) == 0x1f0 || offset == 0x3f6)
+               return IDE_OFFSET + offset;
+       else if((offset & ~0x1f) == 0x300)
+               return NIC_OFFSET + offset;
+       return EXTBUS_OFFSET + offset;
+}
index 615d46148df1faa493ded8a7627fa0c58a94a118..10b9068f8ccb0cd3cf967e819fdadee936968cc7 100644 (file)
 #include <asm/irq.h>
 #include <linux/irq.h>
 
-/*
- * Micro-access to controllers is serialized over the whole
- * system. We never hold this lock when we call the actual
- * IRQ handler.
- */
-spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
 /*
  * Controller mappings for all interrupt sources:
  */
@@ -160,14 +154,15 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction *
  */
 void disable_irq_nosync(unsigned int irq)
 {
+       irq_desc_t *desc = irq_desc + irq;
        unsigned long flags;
 
-       spin_lock_irqsave(&irq_controller_lock, flags);
-       if (!irq_desc[irq].depth++) {
-               irq_desc[irq].status |= IRQ_DISABLED;
-               irq_desc[irq].handler->disable(irq);
+       spin_lock_irqsave(&desc->lock, flags);
+       if (!desc->depth++) {
+               desc->status |= IRQ_DISABLED;
+               desc->handler->disable(irq);
        }
-       spin_unlock_irqrestore(&irq_controller_lock, flags);
+       spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 /*
@@ -187,28 +182,29 @@ void disable_irq(unsigned int irq)
 
 void enable_irq(unsigned int irq)
 {
+       irq_desc_t *desc = irq_desc + irq;
        unsigned long flags;
 
-       spin_lock_irqsave(&irq_controller_lock, flags);
-       switch (irq_desc[irq].depth) {
+       spin_lock_irqsave(&desc->lock, flags);
+       switch (desc->depth) {
        case 1: {
-               unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
-               irq_desc[irq].status = status;
+               unsigned int status = desc->status & ~IRQ_DISABLED;
+               desc->status = status;
                if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
-                       irq_desc[irq].status = status | IRQ_REPLAY;
-                       hw_resend_irq(irq_desc[irq].handler,irq);
+                       desc->status = status | IRQ_REPLAY;
+                       hw_resend_irq(desc->handler,irq);
                }
-               irq_desc[irq].handler->enable(irq);
+               desc->handler->enable(irq);
                /* fall-through */
        }
        default:
-               irq_desc[irq].depth--;
+               desc->depth--;
                break;
        case 0:
                printk("enable_irq() unbalanced from %p\n",
                       __builtin_return_address(0));
        }
-       spin_unlock_irqrestore(&irq_controller_lock, flags);
+       spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 /*
@@ -245,7 +241,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
 
        kstat.irqs[cpu][irq]++;
        desc = irq_desc + irq;
-       spin_lock(&irq_controller_lock);
+       spin_lock(&desc->lock);
        desc->handler->ack(irq);
        /*
           REPLAY is when Linux resends an IRQ that was dropped earlier
@@ -265,7 +261,6 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
                status |= IRQ_INPROGRESS; /* we are handling it */
        }
        desc->status = status;
-       spin_unlock(&irq_controller_lock);
 
        /*
         * If there is no IRQ handler or it was disabled, exit early.
@@ -274,7 +269,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
           will take care of it.
         */
        if (!action)
-               return 1;
+               goto out;
 
        /*
         * Edge triggered interrupts need to remember
@@ -287,23 +282,24 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
         * SMP environment.
         */
        for (;;) {
+               spin_unlock(&desc->lock);
                handle_IRQ_event(irq, &regs, action);
-               spin_lock(&irq_controller_lock);
+               spin_lock(&desc->lock);
 
                if (!(desc->status & IRQ_PENDING))
                        break;
                desc->status &= ~IRQ_PENDING;
-               spin_unlock(&irq_controller_lock);
        }
        desc->status &= ~IRQ_INPROGRESS;
-       if (!(desc->status & IRQ_DISABLED))
-               desc->handler->end(irq);
-       spin_unlock(&irq_controller_lock);
+out:
+       /*
+        * The ->end() handler has to deal with interrupts which got
+        * disabled while the handler was running.
+        */
+       desc->handler->end(irq);
+       spin_unlock(&desc->lock);
 
-#if 0
-       __sti();
-#endif
-       if (softirq_active(cpu)&softirq_mask(cpu))
+       if (softirq_pending(cpu))
                do_softirq();
        return 1;
 }
@@ -342,14 +338,16 @@ int request_irq(unsigned int irq,
 
 void free_irq(unsigned int irq, void *dev_id)
 {
+       irq_desc_t *desc;
        struct irqaction **p;
        unsigned long flags;
 
        if (irq >= ACTUAL_NR_IRQS)
                return;
 
-       spin_lock_irqsave(&irq_controller_lock,flags);
-       p = &irq_desc[irq].action;
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
        for (;;) {
                struct irqaction * action = *p;
                if (action) {
@@ -360,20 +358,22 @@ void free_irq(unsigned int irq, void *dev_id)
 
                        /* Found it - now remove it from the list of entries */
                        *pp = action->next;
-                       if (!irq_desc[irq].action) {
-                               irq_desc[irq].status |= IRQ_DISABLED;
-                               irq_desc[irq].handler->shutdown(irq);
+                       if (!desc->action) {
+                               desc->status |= IRQ_DISABLED;
+                               desc->handler->shutdown(irq);
                        }
-                       spin_unlock_irqrestore(&irq_controller_lock,flags);
+                       spin_unlock_irqrestore(&desc->lock,flags);
                        kfree(action);
                        return;
                }
                printk("Trying to free free IRQ%d\n",irq);
-               spin_unlock_irqrestore(&irq_controller_lock,flags);
+               spin_unlock_irqrestore(&desc->lock,flags);
                return;
        }
 }
 
+static DECLARE_MUTEX(probe_sem);
+
 /*
  * IRQ autodetection code..
  *
@@ -385,21 +385,44 @@ void free_irq(unsigned int irq, void *dev_id)
 unsigned long probe_irq_on(void)
 {
        unsigned int i;
-       unsigned long delay;
+       irq_desc_t *desc;
        unsigned long val;
+       unsigned long delay;
+
+       down(&probe_sem);
+       /* 
+        * something may have generated an irq long ago and we want to
+        * flush such a longstanding irq before considering it as spurious. 
+        */
+       for (i = NR_IRQS-1; i > 0; i--) {
+               desc = irq_desc + i;
+
+               spin_lock_irq(&desc->lock);
+               if (!desc->action)
+                 desc->handler->startup(i);
+               spin_unlock_irq(&desc->lock);
+       }
+
+       /* Wait for longstanding interrupts to trigger. */
+       for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+               /* about 20ms delay */ synchronize_irq();
 
        /*
-        * first, enable any unassigned irqs
+        * enable any unassigned irqs
+        * (we must startup again here because if a longstanding irq
+        * happened in the previous stage, it may have masked itself)
         */
-       spin_lock_irq(&irq_controller_lock);
        for (i = NR_IRQS-1; i > 0; i--) {
-               if (!irq_desc[i].action) {
-                       irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
-                       if (irq_desc[i].handler->startup(i))
-                               irq_desc[i].status |= IRQ_PENDING;
+               desc = irq_desc + i;
+
+               spin_lock_irq(&desc->lock);
+               if (!desc->action) {
+                       desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+                       if (desc->handler->startup(i))
+                               desc->status |= IRQ_PENDING;
                }
+               spin_unlock_irq(&desc->lock);
        }
-       spin_unlock_irq(&irq_controller_lock);
 
        /*
         * Wait for spurious interrupts to trigger
@@ -411,23 +434,25 @@ unsigned long probe_irq_on(void)
         * Now filter out any obviously spurious interrupts
         */
        val = 0;
-       spin_lock_irq(&irq_controller_lock);
        for (i=0; i<NR_IRQS; i++) {
-               unsigned int status = irq_desc[i].status;
-
-               if (!(status & IRQ_AUTODETECT))
-                       continue;
-
-               /* It triggered already - consider it spurious. */
-               if (!(status & IRQ_WAITING)) {
-                       irq_desc[i].status = status & ~IRQ_AUTODETECT;
-                       irq_desc[i].handler->shutdown(i);
+               desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       /* It triggered already - consider it spurious. */
+                       if (!(status & IRQ_WAITING)) {
+                               desc->status = status & ~IRQ_AUTODETECT;
+                               desc->handler->shutdown(i);
+                       } else
+                               if (i < 32)
+                                       val |= 1 << i;
                }
-
-               if (i < 32)
-                       val |= 1 << i;
+               spin_unlock_irq(&desc->lock);
        }
-       spin_unlock_irq(&irq_controller_lock);
+       spin_unlock_irq(&desc->lock);
 
        return val;
 }
@@ -438,22 +463,25 @@ int probe_irq_off(unsigned long val)
 
        nr_irqs = 0;
        irq_found = 0;
-       spin_lock_irq(&irq_controller_lock);
        for (i=0; i<NR_IRQS; i++) {
-               unsigned int status = irq_desc[i].status;
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
 
-               if (!(status & IRQ_AUTODETECT))
-                       continue;
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
 
-               if (!(status & IRQ_WAITING)) {
-                       if (!nr_irqs)
-                               irq_found = i;
-                       nr_irqs++;
+               if (status & IRQ_AUTODETECT) {
+                       if (!(status & IRQ_WAITING)) {
+                               if (!nr_irqs)
+                                       irq_found = i;
+                               nr_irqs++;
+                       }
+                       desc->status = status & ~IRQ_AUTODETECT;
+                       desc->handler->shutdown(i);
                }
-               irq_desc[i].status = status & ~IRQ_AUTODETECT;
-               irq_desc[i].handler->shutdown(i);
+               spin_unlock_irq(&desc->lock);
        }
-       spin_unlock_irq(&irq_controller_lock);
+       up(&probe_sem);
 
        if (nr_irqs > 1)
                irq_found = -irq_found;
@@ -465,6 +493,7 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        int shared = 0;
        struct irqaction *old, **p;
        unsigned long flags;
+       irq_desc_t *desc = irq_desc + irq;
 
        /*
         * Some drivers like serial.c use request_irq() heavily,
@@ -486,12 +515,12 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        /*
         * The following block of code has to be executed atomically
         */
-       spin_lock_irqsave(&irq_controller_lock,flags);
-       p = &irq_desc[irq].action;
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
        if ((old = *p) != NULL) {
                /* Can't share interrupts unless both agree to */
                if (!(old->flags & new->flags & SA_SHIRQ)) {
-                       spin_unlock_irqrestore(&irq_controller_lock,flags);
+                       spin_unlock_irqrestore(&desc->lock,flags);
                        return -EBUSY;
                }
 
@@ -506,11 +535,11 @@ int setup_irq(unsigned int irq, struct irqaction * new)
        *p = new;
 
        if (!shared) {
-               irq_desc[irq].depth = 0;
-               irq_desc[irq].status &= ~IRQ_DISABLED;
-               irq_desc[irq].handler->startup(irq);
+               desc->depth = 0;
+               desc->status &= ~IRQ_DISABLED;
+               desc->handler->startup(irq);
        }
-       spin_unlock_irqrestore(&irq_controller_lock,flags);
+       spin_unlock_irqrestore(&desc->lock,flags);
        return 0;
 }
 
index 7a995cdafb3ea8b99bde51abb8e3a40dac05362f..b6bd635481f6bf7c1d9c54b1a7e93a785fab4c57 100644 (file)
@@ -45,7 +45,7 @@ static unsigned int startup_intc2_irq(unsigned int irq)
 }
 
 static struct hw_interrupt_type intc2_irq_type = {
-       "INTC2-based-IRQ",
+       "INTC2-IRQ",
        startup_intc2_irq,
        shutdown_intc2_irq,
        enable_intc2_irq,
index 93fd32920ad678ef1ae3467a3562a2b5f5800103..fb9636ff022a902d4216138f7a7344b5f7faae64 100644 (file)
@@ -46,7 +46,7 @@ static unsigned int startup_ipr_irq(unsigned int irq)
 }
 
 static struct hw_interrupt_type ipr_irq_type = {
-       "IPR-based-IRQ",
+       "IPR-IRQ",
        startup_ipr_irq,
        shutdown_ipr_irq,
        enable_ipr_irq,
@@ -189,7 +189,9 @@ void make_pint_irq(unsigned int irq)
 
 void __init init_IRQ(void)
 {
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
        int i;
+#endif
 
        make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
        make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
@@ -226,27 +228,6 @@ void __init init_IRQ(void)
         * Initialize the Interrupt Controller (INTC)
         * registers to their power on values
         */ 
-#if 0
-       /*
-        * XXX: I think that this is the job of boot loader. -- gniibe
-        *
-        * When Takeshi released new boot loader following setting
-        * will be removed shortly.
-        */
-       ctrl_outb(0, INTC_IRR0);
-       ctrl_outb(0, INTC_IRR1);
-       ctrl_outb(0, INTC_IRR2);
-
-       ctrl_outw(0, INTC_ICR0);
-       ctrl_outw(0, INTC_ICR1);/* Really? 0x4000?*/
-       ctrl_outw(0, INTC_ICR2);
-       ctrl_outw(0, INTC_INTER);
-       ctrl_outw(0, INTC_IPRA);
-       ctrl_outw(0, INTC_IPRB);
-       ctrl_outw(0, INTC_IPRC);
-       ctrl_outw(0, INTC_IPRD);
-       ctrl_outw(0, INTC_IPRE);
-#endif
 
        /*
         * Enable external irq (INTC IRQ mode).
diff --git a/arch/sh/kernel/led_bigsur.c b/arch/sh/kernel/led_bigsur.c
new file mode 100644 (file)
index 0000000..7155dfa
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/sh/kernel/led_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from led_se.c and led.c, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * This file contains Big Sur specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/bigsur.h>
+
+static void mach_led(int position, int value)
+{
+       int word;
+       
+       word = bigsur_inl(BIGSUR_CSLR);
+       if (value) {
+               bigsur_outl(word & ~BIGSUR_LED, BIGSUR_CSLR);
+       } else {
+               bigsur_outl(word | BIGSUR_LED, BIGSUR_CSLR);
+       }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED on/off */
+void heartbeat_bigsur(void)
+{
+       static unsigned cnt = 0, period = 0, dist = 0;
+
+       if (cnt == 0 || cnt == dist)
+               mach_led( -1, 1);
+       else if (cnt == 7 || cnt == dist+7)
+               mach_led( -1, 0);
+
+       if (++cnt > period) {
+               cnt = 0;
+               /* The hyperbolic function below modifies the heartbeat period
+                * length in dependency of the current (5min) load. It goes
+                * through the points f(0)=126, f(1)=86, f(5)=51,
+                * f(inf)->30. */
+               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+               dist = period / 4;
+       }
+}
+#endif /* CONFIG_HEARTBEAT */
+
diff --git a/arch/sh/kernel/mach_bigsur.c b/arch/sh/kernel/mach_bigsur.c
new file mode 100644 (file)
index 0000000..65d9840
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * linux/arch/sh/kernel/mach_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from mach_se.h, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Machine vector for the Hitachi Big Sur Evaluation Board
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io.h>
+#include <asm/io_bigsur.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+extern void heartbeat_bigsur(void);
+extern void setup_bigsur(void);
+extern void init_bigsur_IRQ(void);
+
+struct sh_machine_vector mv_bigsur __initmv = {
+       mv_name:                "Big Sur",
+       mv_nr_irqs:             NR_IRQS,     // Defined in <asm/irq.h>
+       mv_inb:                 bigsur_inb,
+       mv_inw:                 bigsur_inw,
+       mv_inl:                 bigsur_inl,
+       mv_outb:                bigsur_outb,
+       mv_outw:                bigsur_outw,
+       mv_outl:                bigsur_outl,
+
+       mv_inb_p:               bigsur_inb_p,
+       mv_inw_p:               bigsur_inw,
+       mv_inl_p:               bigsur_inl,
+       mv_outb_p:              bigsur_outb_p,
+       mv_outw_p:              bigsur_outw,
+       mv_outl_p:              bigsur_outl,
+
+       mv_insb:                bigsur_insb,
+       mv_insw:                bigsur_insw,
+       mv_insl:                bigsur_insl,
+       mv_outsb:               bigsur_outsb,
+       mv_outsw:               bigsur_outsw,
+       mv_outsl:               bigsur_outsl,
+
+       mv_readb:               generic_readb,
+       mv_readw:               generic_readw,
+       mv_readl:               generic_readl,
+       mv_writeb:              generic_writeb,
+       mv_writew:              generic_writew,
+       mv_writel:              generic_writel,
+
+       mv_ioremap:             generic_ioremap,
+       mv_iounmap:             generic_iounmap,
+
+       mv_isa_port2addr:       bigsur_isa_port2addr,
+       mv_irq_demux:       bigsur_irq_demux,
+
+       mv_init_arch:           setup_bigsur,
+       mv_init_irq:            init_bigsur_IRQ,
+#ifdef CONFIG_HEARTBEAT
+       mv_heartbeat:           heartbeat_bigsur,
+#endif
+       mv_rtc_gettimeofday:    sh_rtc_gettimeofday,
+       mv_rtc_settimeofday:    sh_rtc_settimeofday,
+
+};
+ALIAS_MV(bigsur)
index 2bffc7ea30c00f57eebe6234966504a734be56e3..ee725e7bba9b0a0edfbf2fb0a01deb3256b57856 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     $Id: mach_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *     $Id: mach_dc.c,v 1.4 2001/05/24 05:09:16 mrbrown Exp $
  *     SEGA Dreamcast machine vector
  */
 
@@ -23,7 +23,7 @@ void __init dreamcast_pcibios_init(void);
 struct sh_machine_vector mv_dreamcast __initmv = {
        mv_name:                "dreamcast",
 
-       mv_nr_irqs:             48,
+       mv_nr_irqs:             NR_IRQS,
 
        mv_inb:                 generic_inb,
        mv_inw:                 generic_inw,
@@ -57,11 +57,9 @@ struct sh_machine_vector mv_dreamcast __initmv = {
        mv_iounmap:             generic_iounmap,
 
        mv_init_arch:           setup_dreamcast,
-#ifdef CONFIG_PCI
-       mv_init_pci:            dreamcast_pcibios_init,
-#endif
        mv_isa_port2addr:       dreamcast_isa_port2addr,
+       mv_irq_demux:           systemasic_irq_demux,
 
-       mv_hw_dreamcast:                1,
+       mv_hw_dreamcast:        1,
 };
 ALIAS_MV(dreamcast)
diff --git a/arch/sh/kernel/pci-7751se.c b/arch/sh/kernel/pci-7751se.c
new file mode 100644 (file)
index 0000000..5304f6a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/sh/kernel/pci-7751se.c
+ *
+ * Author:  Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi SH7751 Solution Engine board (MS7751SE01)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+
+#define PCIMCR_MRSET_OFF       0xBFFFFFFF
+#define PCIMCR_RFSH_OFF                0xFFFFFFFB
+
+/*
+ * Only long word accesses of the PCIC's internal local registers and the
+ * configuration registers from the CPU is supported.
+ */
+#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+#define PCIC_READ(x) readl(PCI_REG(x))
+
+/*
+ * Description:  This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+   unsigned long data;
+   unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+   unsigned short bcr2;
+
+   //
+   // Initialize the slave bus controller on the pcic.  The values used
+   // here should not be hardcoded, but they should be taken from the bsc
+   // on the processor, to make this function as generic as possible.
+   // (i.e. Another sbc may usr different SDRAM timing settings -- in order
+   // for the pcic to work, its settings need to be exactly the same.)
+   //
+   bcr1 = (*(volatile unsigned long*)(SH7751_BCR1));
+   bcr2 = (*(volatile unsigned short*)(SH7751_BCR2));
+   wcr1 = (*(volatile unsigned long*)(SH7751_WCR1));
+   wcr2 = (*(volatile unsigned long*)(SH7751_WCR2));
+   wcr3 = (*(volatile unsigned long*)(SH7751_WCR3));
+   mcr = (*(volatile unsigned long*)(SH7751_MCR));
+
+   bcr1 = bcr1 | 0x00080000;  /* Enable Bit 19, BREQEN */
+   (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1;   
+
+   bcr1 = bcr1 | 0x40080000;  /* Enable Bit 19 BREQEN, set PCIC to slave */
+   PCIC_WRITE(SH7751_PCIBCR1, bcr1);    /* PCIC BCR1 */
+   PCIC_WRITE(SH7751_PCIBCR2, bcr2);     /* PCIC BCR2 */
+   PCIC_WRITE(SH7751_PCIWCR1, wcr1);     /* PCIC WCR1 */
+   PCIC_WRITE(SH7751_PCIWCR2, wcr2);     /* PCIC WCR2 */
+   PCIC_WRITE(SH7751_PCIWCR3, wcr3);     /* PCIC WCR3 */
+   mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+   PCIC_WRITE(SH7751_PCIMCR, mcr);      /* PCIC MCR */
+
+   PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+   PCIC_WRITE(SH7751_PCIAINTM, 0x0000980f);
+   PCIC_WRITE(SH7751_PCICONF1, 0xF39000C7);  /* FB9000C7 */
+   PCIC_WRITE(SH7751_PCICONF2, 0x00000000);  /* PCI Class code & Revision ID */
+   PCIC_WRITE(SH7751_PCICONF4, 0xab000001);  /* PCI I/O */
+   PCIC_WRITE(SH7751_PCICONF5, 0x0c000000);  /* PCI MEM0 old val: 0xb0000000 */
+   PCIC_WRITE(SH7751_PCICONF6, 0xd0000000);  /* PCI MEM1 */
+   PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Sub system ID & Sub system vendor ID */
+   PCIC_WRITE(SH7751_PCILSR0, 0x03f00000);   /* PCI MEM0 */
+   PCIC_WRITE(SH7751_PCILSR1, 0x00000000);   /* PCI MEM1 */
+   PCIC_WRITE(SH7751_PCILAR0, 0x0c000000);   /* MEM0 */
+   PCIC_WRITE(SH7751_PCILAR1, 0x00000000);   /* MEM1 */
+
+   PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+
+   printk("SH7751 PCI: Finished initialization of the PCI controller\n");
+
+   return 1;
+}
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+        switch (slot) {
+        case 0: return 13;
+        case 1: return 13;     /* AMD Ethernet controller */
+        case 2: return -1;
+        case 3: return -1;
+        case 4: return -1;
+        default:
+                printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+                return -1;
+        }
+}
diff --git a/arch/sh/kernel/pci-bigsur.c b/arch/sh/kernel/pci-bigsur.c
new file mode 100644 (file)
index 0000000..cc1eacd
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * linux/arch/sh/kernel/pci-bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi Big Sur Evaluation Board
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+#include <asm/bigsur.h>
+
+#define PCI_REG(reg)        (SH7751_PCIREG_BASE+reg)
+
+/*
+ * Initialize the Big Sur PCI interface 
+ * Setup hardware to be Central Funtion
+ * Copy the BSR regs to the PCI interface
+ * Setup PCI windows into local RAM
+ */
+int __init pcibios_init_platform(void) {
+       u32 reg;
+       u32 word;
+
+       PCIDBG(1,"PCI: bigsur_pci_init called\n");
+       /* Set the BCR's to enable PCI access */
+       reg = inl(SH7751_BCR1);
+       reg |= 0x80000;
+       outl(reg, SH7751_BCR1);
+       
+       /* Setup the host hardware */
+       if(inl(PCI_REG(SH7751_PCICONF0)) !=
+          (u32)((SH7751_DEVICE_ID <<16) | (SH7751_VENDOR_ID))) {
+          printk("PCI: Unkown PCI host bridge.\n");
+          return 0;
+       }  
+       printk("PCI: SH7751 PCI host bridge found.\n");
+       
+       /* Turn the clocks back on (not done in reset)*/
+       outl(0, PCI_REG(SH7751_PCICLKR));
+       /* Clear Powerdown IRQ's (not done in reset) */
+       word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0;
+       outl(word, PCI_REG(SH7751_PCICLKR));
+
+       /* toggle PCI reset pin */
+       word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
+       outl(word,PCI_REG(SH7751_PCICR));    
+       /* Wait for a long time... not 1 sec. but long enough */
+       mdelay(100);
+       word = SH7751_PCICR_PREFIX;
+       outl(word,PCI_REG(SH7751_PCICR)); 
+       
+    /* set the command/status bits to:
+     * Wait Cycle Control + Parity Enable + Bus Master +
+     * Mem space enable
+     */
+    word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | 
+           SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
+       outl(word, PCI_REG(SH7751_PCICONF1));
+
+       /* define this host as the host bridge */
+       word = SH7751_PCI_HOST_BRIDGE << 24;
+       outl(word, PCI_REG(SH7751_PCICONF2));
+
+       /* Set IO and Mem windows to local address 
+        * Make PCI and local address the same for easy 1 to 1 mapping 
+        * Window0 = BIGSUR_LSR0_SIZE @ non-cached CS3 base = SDRAM
+        * Window1 = BIGSUR_LSR1_SIZE @ cached CS3 base = SDRAM 
+        */
+       word = BIGSUR_LSR0_SIZE - 1;
+       outl(word, PCI_REG(SH7751_PCILSR0));
+       word = BIGSUR_LSR1_SIZE - 1;
+       outl(word, PCI_REG(SH7751_PCILSR1));
+       /* Set the values on window 0 PCI config registers */
+       word = P2SEGADDR(SH7751_CS3_BASE_ADDR);
+       outl(word, PCI_REG(SH7751_PCILAR0));
+       outl(word, PCI_REG(SH7751_PCICONF5));
+       /* Set the values on window 1 PCI config registers */
+       word =  PHYSADDR(SH7751_CS3_BASE_ADDR);
+       outl(word, PCI_REG(SH7751_PCILAR1));
+       outl(word, PCI_REG(SH7751_PCICONF6));
+
+       /* Set the local 16MB PCI memory space window to 
+        * the lowest PCI mapped address
+        */
+       word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK;
+       PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word);
+       outl(word , PCI_REG(SH7751_PCIMBR));
+
+       /* Map IO space into PCI IO window
+        * The IO window is 64K-PCIBIOS_MIN_IO in size
+        * IO addresses will be translated to the 
+        * PCI IO window base address
+        */
+       PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO,
+           (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO);
+       bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
+           
+       /* Make sure the MSB's of IO window are set to access PCI space correctly */
+       word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK;
+       PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word);
+       outl(word, PCI_REG(SH7751_PCIIOBR));
+       
+       /* Set PCI WCRx, BCRx's, copy from BSC locations */
+       word = inl(SH7751_BCR1);
+       /* check BCR for SDRAM in area 3 */
+       if(((word >> 3) & 1) == 0) {
+               printk("PCI: Area 3 is not configured for SDRAM. BCR1=0x%x\n", word);
+               return 0;
+       }
+       outl(word, PCI_REG(SH7751_PCIBCR1));
+       word = (u16)inw(SH7751_BCR2);
+       /* check BCR2 for 32bit SDRAM interface*/
+       if(((word >> 6) & 0x3) != 0x3) {
+               printk("PCI: Area 3 is not 32 bit SDRAM. BCR2=0x%x\n", word);
+               return 0;
+       }
+       outl(word, PCI_REG(SH7751_PCIBCR2));
+       /* configure the wait control registers */
+       word = inl(SH7751_WCR1);
+       outl(word, PCI_REG(SH7751_PCIWCR1));
+       word = inl(SH7751_WCR2);
+       outl(word, PCI_REG(SH7751_PCIWCR2));
+       word = inl(SH7751_WCR3);
+       outl(word, PCI_REG(SH7751_PCIWCR3));
+       word = inl(SH7751_MCR);
+       outl(word, PCI_REG(SH7751_PCIMCR));
+
+       /* NOTE: I'm ignoring the PCI error IRQs for now..
+        * TODO: add support for the internal error interrupts and
+        * DMA interrupts...
+        */
+        
+       /* SH7751 init done, set central function init complete */
+       word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN;
+       outl(word,PCI_REG(SH7751_PCICR)); 
+       PCIDBG(2,"PCI: bigsur_pci_init finished\n");
+
+       return 1;
+}
+
+int pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+    /* The Big Sur can be used in a CPCI chassis, but the SH7751 PCI interface is on the
+     * wrong end of the board so that it can also support a V320 CPI interface chip...
+     * Therefor the IRQ mapping is somewhat use dependent... I'l assume a linear map for
+     * now, i.e. INTA=slot0,pin0... INTD=slot3,pin0...
+     */ 
+    int irq = (slot + pin-1)%4 + BIGSUR_SH7751_PCI_IRQ_BASE;
+    PCIDBG(2,"PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", slot, pin-1+'A', irq);
+    return irq;
+     
+}
diff --git a/arch/sh/kernel/pci-dc.c b/arch/sh/kernel/pci-dc.c
new file mode 100644 (file)
index 0000000..b2516b5
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ $     $Id: pci-dc.c,v 1.2 2001/05/24 05:09:16 mrbrown Exp $
+ *     Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dc_sysasic.h>
+
+#define        GAPSPCI_REGS            0x01001400
+#define GAPSPCI_DMA_BASE       0x01840000
+#define GAPSPCI_DMA_SIZE       32768
+#define GAPSPCI_BBA_CONFIG     0x01001600
+
+#define        GAPSPCI_IRQ             HW_EVENT_EXTERNAL
+
+static int gapspci_dma_used;
+
+static struct pci_bus *pci_root_bus;
+
+struct pci_fixup pcibios_fixups[] = {
+       {0, 0, 0, NULL}
+};
+
+#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
+
+static int gapspci_read_config_byte(struct pci_dev *dev, int where,
+                                    u8 * val)
+{
+       if (BBA_SELECTED(dev))
+               *val = inb(GAPSPCI_BBA_CONFIG+where);
+       else
+                *val = 0xff;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_word(struct pci_dev *dev, int where,
+                                    u16 * val)
+{
+        if (BBA_SELECTED(dev))
+               *val = inw(GAPSPCI_BBA_CONFIG+where);
+       else
+                *val = 0xffff;
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_dword(struct pci_dev *dev, int where,
+                                     u32 * val)
+{
+        if (BBA_SELECTED(dev))
+               *val = inl(GAPSPCI_BBA_CONFIG+where);
+       else
+                *val = 0xffffffff;
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_byte(struct pci_dev *dev, int where,
+                                     u8 val)
+{
+        if (BBA_SELECTED(dev))
+               outb(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int gapspci_write_config_word(struct pci_dev *dev, int where,
+                                     u16 val)
+{
+        if (BBA_SELECTED(dev))
+               outw(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_dword(struct pci_dev *dev, int where,
+                                      u32 val)
+{
+        if (BBA_SELECTED(dev))
+               outl(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_config_ops = {
+        gapspci_read_config_byte,
+        gapspci_read_config_word,
+        gapspci_read_config_dword,
+        gapspci_write_config_byte,
+        gapspci_write_config_word,
+        gapspci_write_config_dword
+};
+
+
+void pcibios_align_resource(void *data, struct resource *res,
+                           unsigned long size)
+{
+}
+
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+}
+
+
+void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                            struct resource *res, int resource)
+{
+}
+
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for (idx = 0; idx < 6; idx++) {
+               r = dev->resource + idx;
+               if (!r->start && r->end) {
+                       printk(KERN_ERR
+                              "PCI: Device %s not available because"
+                              " of resource collisions\n",
+                              dev->slot_name);
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (cmd != old_cmd) {
+               printk("PCI: enabling device %s (%04x -> %04x)\n",
+                      dev->slot_name, old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+
+}
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                          dma_addr_t * dma_handle)
+{
+       unsigned long buf;
+
+       if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
+               return NULL;
+
+       buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
+
+       gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
+       
+       printk("pci_alloc_consistent: %ld bytes at 0x%p\n", size, buf);
+
+       *dma_handle = (dma_addr_t)buf;
+
+       return (void *)P2SEGADDR(buf);
+}
+
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       /* XXX */
+}
+
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+}                                                                                
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+       struct list_head *ln;
+       struct pci_dev *dev;
+
+       for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+               dev = pci_dev_b(ln);
+               if (!BBA_SELECTED(dev)) continue;
+
+               printk("PCI: MMIO fixup to %s\n", dev->name);
+               dev->resource[1].start=0x01001700;
+               dev->resource[1].end=0x010017ff;
+       }
+}
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+       return PCI_SLOT(dev->devfn);
+}
+
+
+static int __init map_dc_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return GAPSPCI_IRQ;
+}
+
+
+void __init pcibios_init(void)
+{
+       pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+       /* pci_assign_unassigned_resources(); */
+       pci_fixup_irqs(no_swizzle, map_dc_irq);
+}
+
+
+/* Haven't done anything here as yet */
+char * __init pcibios_setup(char *str)
+{
+       return str;
+}
+
+
+int __init gapspci_init(void)
+{
+       int i;
+       char idbuf[16];
+
+       for(i=0; i<16; i++)
+               idbuf[i]=inb(GAPSPCI_REGS+i);
+
+       if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
+               return -1;
+
+       outl(0x5a14a501, GAPSPCI_REGS+0x18);
+
+       for(i=0; i<1000000; i++);
+
+       if(inl(GAPSPCI_REGS+0x18)!=1)
+               return -1;
+
+       outl(0x01000000, GAPSPCI_REGS+0x20);
+       outl(0x01000000, GAPSPCI_REGS+0x24);
+
+       outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
+       outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
+
+       outl(1, GAPSPCI_REGS+0x14);
+       outl(1, GAPSPCI_REGS+0x34);
+
+       gapspci_dma_used=0;
+
+       /* Setting Broadband Adapter */
+       outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
+       outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
+       outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
+       outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
+       outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
+       outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
+       outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
+
+       return 0;
+}
diff --git a/arch/sh/kernel/pci-dma.c b/arch/sh/kernel/pci-dma.c
new file mode 100644 (file)
index 0000000..4753113
--- /dev/null
@@ -0,0 +1,42 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                          dma_addr_t * dma_handle)
+{
+       void *ret;
+       int gfp = GFP_ATOMIC;
+
+       ret = (void *) __get_free_pages(gfp, get_order(size));
+
+       if (ret != NULL) {
+               /* Is it neccessary to do the memset? */
+               memset(ret, 0, size);
+               *dma_handle = virt_to_bus(ret);
+       }
+       /* We must flush the cache before we pass it on to the device */
+       flush_cache_all();
+       return  P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+        unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+       free_pages(p1addr, get_order(size));
+}
diff --git a/arch/sh/kernel/pci-sh.c b/arch/sh/kernel/pci-sh.c
deleted file mode 100644 (file)
index a4a6c69..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <asm/machvec.h>
-
-void __init pcibios_init(void)
-{
-       if (sh_mv.mv_init_pci != NULL) {
-               sh_mv.mv_init_pci();
-       }
-}
-
-/* Haven't done anything here as yet */
-char * __init pcibios_setup(char *str)
-{
-       return str;
-}
-
-/* We don't have anything here to fixup */
-struct pci_fixup pcibios_fixups[] = {
-       {0, 0, 0, NULL}
-};
diff --git a/arch/sh/kernel/pci-sh7751.c b/arch/sh/kernel/pci-sh7751.c
new file mode 100644 (file)
index 0000000..fca62b3
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ *     Low-Level PCI Support for the SH7751
+ *
+ *  Dustin McIntire (dustin@sensoria.com)
+ *     Derived from arch/i386/kernel/pci-*.c which bore the message:
+ *     (c) 1999--2000 Martin Mares <mj@suse.cz>
+ *     
+ *  May be copied or modified under the terms of the GNU General Public
+ *  License.  See linux/COPYING for more information.
+ *
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+
+#include <asm/segment.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+
+struct pci_ops *pci_check_direct(void);
+void pcibios_resource_survey(void);
+static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin);
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin);
+
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1;
+int pcibios_last_bus = -1;
+struct pci_bus *pci_root_bus;
+struct pci_ops *pci_root_ops;
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+#ifdef CONFIG_PCI_DIRECT
+
+
+#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+       u32 word;
+       unsigned long flags;
+
+    /* PCIPDR may only be accessed as 32 bit words, 
+     * so we must do byte alignment by hand 
+     */
+       __save_and_cli(flags);
+       outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+       word = inl(PCI_REG(SH7751_PCIPDR));
+       __restore_flags(flags);
+       switch (where & 0x3) {
+           case 3:
+                   *value = (u8)(word >> 24);
+                       break;
+               case 2:
+                   *value = (u8)(word >> 16);
+                       break;
+               case 1:
+                   *value = (u8)(word >> 8);
+                       break;
+               default:
+                   *value = (u8)word;
+                       break;
+    }
+       PCIDBG(4,"pci_conf1_read_config_byte@0x%08x=0x%x\n",
+            CONFIG_CMD(dev,where),*value);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+       u32 word;
+       unsigned long flags;
+
+    /* PCIPDR may only be accessed as 32 bit words, 
+     * so we must do word alignment by hand 
+     */
+       __save_and_cli(flags);
+       outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+       word = inl(PCI_REG(SH7751_PCIPDR));
+       __restore_flags(flags);
+       switch (where & 0x3) {
+           case 3:
+                   // This should never happen...
+                       printk(KERN_ERR "PCI BIOS: read_config_word: Illegal u16 alignment");
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+               case 2:
+                   *value = (u16)(word >> 16);
+                       break;
+               case 1:
+                   *value = (u16)(word >> 8);
+                       break;
+               default:
+                   *value = (u16)word;
+                       break;
+    }
+       PCIDBG(4,"pci_conf1_read_config_word@0x%08x=0x%x\n",
+            CONFIG_CMD(dev,where),*value);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+       unsigned long flags;
+       
+       __save_and_cli(flags);
+       outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+       *value = inl(PCI_REG(SH7751_PCIPDR));
+       __restore_flags(flags);
+       PCIDBG(4,"pci_conf1_read_config_dword@0x%08x=0x%x\n",
+            CONFIG_CMD(dev,where),*value);
+       return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+       u32 word;
+       u32 shift = (where & 3) * 8;
+       u32 mask = ((1 << 8) - 1) << shift;  // create the byte mask
+       unsigned long flags;
+
+    /* Since SH7751 only does 32bit access we'll have to do a
+     * read,mask,write operation
+     */ 
+       __save_and_cli(flags);
+       outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+       word = inl(PCI_REG(SH7751_PCIPDR)) ;
+       word &= ~mask;
+       word |= value << shift;
+       outl(word, PCI_REG(SH7751_PCIPDR));
+       __restore_flags(flags);
+       PCIDBG(4,"pci_conf1_write_config_byte@0x%08x=0x%x\n",
+            CONFIG_CMD(dev,where),word);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+       u32 word;
+       u32 shift = (where & 3) * 8;
+       u32 mask = ((1 << 16) - 1) << shift;  // create the word mask
+       unsigned long flags;
+
+    /* Since SH7751 only does 32bit access we'll have to do a
+     * read,mask,write operation.  We'll allow an odd byte offset,
+        * though it should be illegal.
+     */ 
+       if (shift == 24)
+           return PCIBIOS_BAD_REGISTER_NUMBER;
+       __save_and_cli(flags);
+       outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+       word = inl(PCI_REG(SH7751_PCIPDR)) ;
+       word &= ~mask;
+       word |= value << shift;
+       outl(value, PCI_REG(SH7751_PCIPDR));
+       __restore_flags(flags);
+       PCIDBG(4,"pci_conf1_write_config_word@0x%08x=0x%x\n",
+            CONFIG_CMD(dev,where),word);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+       unsigned long flags;
+
+       __save_and_cli(flags);
+       outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+       outl(value, PCI_REG(SH7751_PCIPDR));
+       __restore_flags(flags);
+       PCIDBG(4,"pci_conf1_write_config_dword@0x%08x=0x%x\n",
+            CONFIG_CMD(dev,where),value);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops pci_direct_conf1 = {
+       pci_conf1_read_config_byte,
+       pci_conf1_read_config_word,
+       pci_conf1_read_config_dword,
+       pci_conf1_write_config_byte,
+       pci_conf1_write_config_word,
+       pci_conf1_write_config_dword
+};
+
+struct pci_ops * __init pci_check_direct(void)
+{
+       unsigned int tmp, id;
+
+       /* check for SH7751 hardware */
+       id = (SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID;
+       if(inl(SH7751_PCIREG_BASE+SH7751_PCICONF0) != id) {
+               PCIDBG(2,"PCI: This is not an SH7751\n");
+               return NULL;
+       }
+       /*
+        * Check if configuration works.
+        */
+       if (pci_probe & PCI_PROBE_CONF1) {
+               tmp = inl (PCI_REG(SH7751_PCIPAR));
+               outl (0x80000000, PCI_REG(SH7751_PCIPAR));
+               if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
+                       outl (tmp, PCI_REG(SH7751_PCIPAR));
+                       printk(KERN_INFO "PCI: Using configuration type 1\n");
+                       request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
+                       return &pci_direct_conf1;
+               }
+               outl (tmp, PCI_REG(SH7751_PCIPAR));
+       }
+
+       PCIDBG(2,"PCI: pci_check_direct failed\n");
+       return NULL;
+}
+
+#endif
+
+/*
+ * BIOS32 and PCI BIOS handling.
+ * 
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness.  Currently an error will be genereated at compile time. 
+ */
+#ifdef CONFIG_PCI_BIOS
+
+#error PCI BIOS is not yet supported on SH7751
+
+#endif /* CONFIG_PCI_BIOS */
+
+/***************************************************************************************/
+
+/*
+ *  Handle bus scanning and fixups ....
+ */
+
+
+/*
+ * Discover remaining PCI buses in case there are peer host bridges.
+ * We use the number of last PCI bus provided by the PCI BIOS.
+ */
+static void __init pcibios_fixup_peer_bridges(void)
+{
+       int n;
+       struct pci_bus bus;
+       struct pci_dev dev;
+       u16 l;
+
+       if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
+               return;
+       PCIDBG(2,"PCI: Peer bridge fixup\n");
+       for (n=0; n <= pcibios_last_bus; n++) {
+               if (pci_bus_exists(&pci_root_buses, n))
+                       continue;
+               bus.number = n;
+               bus.ops = pci_root_ops;
+               dev.bus = &bus;
+               for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
+                       if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
+                           l != 0x0000 && l != 0xffff) {
+                               PCIDBG(3,"Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
+                               printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
+                               pci_scan_bus(n, pci_root_ops, NULL);
+                               break;
+                       }
+       }
+}
+
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+       int i;
+
+       /*
+        * PCI IDE controllers use non-standard I/O port decoding, respect it.
+        */
+       if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return;
+       PCIDBG(3,"PCI: IDE base address fixup for %s\n", d->slot_name);
+       for(i=0; i<4; i++) {
+               struct resource *r = &d->resource[i];
+               if ((r->start & ~0x80) == 0x374) {
+                       r->start |= 2;
+                       r->end = r->start;
+               }
+       }
+}
+
+
+/* Add future fixups here... */
+struct pci_fixup pcibios_fixups[] = {
+       { PCI_FIXUP_HEADER,     PCI_ANY_ID,     PCI_ANY_ID,     pci_fixup_ide_bases },
+       { 0 }
+};
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *b,
+               struct pbus_set_ranges_data *range)
+{
+       /* No fixups needed */
+}
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+       pci_read_bridge_bases(b);
+}
+
+/*
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space.
+ * 
+ * Note that the platform specific initialization (BSC registers, and memory
+ * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
+ * exitst and via the platform defined function pcibios_init_platform().  
+ * See pci_bigsur.c for implementation;
+ * 
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness.  Currently an error will be genereated at compile time. 
+ */
+
+void __init pcibios_init(void)
+{
+       struct pci_ops *bios = NULL;
+       struct pci_ops *dir = NULL;
+
+       PCIDBG(1,"PCI: Starting intialization.\n");
+#ifdef CONFIG_PCI_BIOS
+       if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
+               pci_probe |= PCI_BIOS_SORT;
+               pci_bios_present = 1;
+       }
+#endif
+#ifdef CONFIG_PCI_DIRECT
+       if (pci_probe & PCI_PROBE_CONF1 )
+               dir = pci_check_direct();
+#endif
+       if (dir) {
+               pci_root_ops = dir;
+           if(!pcibios_init_platform())
+                       PCIDBG(1,"PCI: Initialization failed\n");
+           if (sh_mv.mv_init_pci != NULL)
+            sh_mv.mv_init_pci();
+       }
+       else if (bios)
+               pci_root_ops = bios;
+       else {
+               PCIDBG(1,"PCI: No PCI bus detected\n");
+               return;
+       }
+
+       PCIDBG(1,"PCI: Probing PCI hardware\n");
+       pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+       //pci_assign_unassigned_resources();
+       pci_fixup_irqs(pcibios_swizzle, pcibios_lookup_irq);
+       pcibios_fixup_peer_bridges();
+       pcibios_resource_survey();
+
+#ifdef CONFIG_PCI_BIOS
+       if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+               pcibios_sort();
+#endif
+}
+
+char * __init pcibios_setup(char *str)
+{
+       if (!strcmp(str, "off")) {
+               pci_probe = 0;
+               return NULL;
+       }
+#ifdef CONFIG_PCI_BIOS
+       else if (!strcmp(str, "bios")) {
+               pci_probe = PCI_PROBE_BIOS;
+               return NULL;
+       } else if (!strcmp(str, "nobios")) {
+               pci_probe &= ~PCI_PROBE_BIOS;
+               return NULL;
+       } else if (!strcmp(str, "nosort")) {
+               pci_probe |= PCI_NO_SORT;
+               return NULL;
+       } else if (!strcmp(str, "biosirq")) {
+               pci_probe |= PCI_BIOS_IRQ_SCAN;
+               return NULL;
+       }
+#endif
+#ifdef CONFIG_PCI_DIRECT
+       else if (!strcmp(str, "conf1")) {
+               pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+               return NULL;
+       }
+#endif
+       else if (!strcmp(str, "rom")) {
+               pci_probe |= PCI_ASSIGN_ROMS;
+               return NULL;
+       } else if (!strncmp(str, "lastbus=", 8)) {
+               pcibios_last_bus = simple_strtol(str+8, NULL, 0);
+               return NULL;
+       }
+       return str;
+}
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                       struct resource *res, int resource)
+{
+       u32 new, check;
+       int reg;
+
+       new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+       if (resource < 6) {
+               reg = PCI_BASE_ADDRESS_0 + 4*resource;
+       } else if (resource == PCI_ROM_RESOURCE) {
+               res->flags |= PCI_ROM_ADDRESS_ENABLE;
+               new |= PCI_ROM_ADDRESS_ENABLE;
+               reg = dev->rom_base_reg;
+       } else {
+               /* Somebody might have asked allocation of a non-standard resource */
+               return;
+       }
+       
+       pci_write_config_dword(dev, reg, new);
+       pci_read_config_dword(dev, reg, &check);
+       if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+               printk(KERN_ERR "PCI: Error while updating region "
+                      "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+                      new, check);
+       }
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+       if (res->flags & IORESOURCE_IO) {
+               unsigned long start = res->start;
+
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
+}
+
+
+/*
+ *    Allocate the bridge and device resources
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+       struct list_head *ln;
+       struct pci_bus *bus;
+       struct pci_dev *dev;
+       int idx;
+       struct resource *r, *pr;
+       
+       PCIDBG(2,"PCI: pcibios_allocate_bus_reasources called\n" );
+       /* Depth-First Search on bus tree */
+       for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+               bus = pci_bus_b(ln);
+               if ((dev = bus->self)) {
+                       for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+                               r = &dev->resource[idx];
+                               if (!r->start)
+                                       continue;
+                               pr = pci_find_parent_resource(dev, r);
+                               if (!pr || request_resource(pr, r) < 0)
+                                       printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+                       }
+               }
+               pcibios_allocate_bus_resources(&bus->children);
+       }
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+       struct pci_dev *dev;
+       int idx, disabled;
+       u16 command;
+       struct resource *r, *pr;
+
+       PCIDBG(2,"PCI: pcibios_allocate_resources pass %d called\n", pass);
+       pci_for_each_dev(dev) {
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               for(idx = 0; idx < 6; idx++) {
+                       r = &dev->resource[idx];
+                       if (r->parent)          /* Already allocated */
+                               continue;
+                       if (!r->start)          /* Address not assigned at all */
+                               continue;
+                       if (r->flags & IORESOURCE_IO)
+                               disabled = !(command & PCI_COMMAND_IO);
+                       else
+                               disabled = !(command & PCI_COMMAND_MEMORY);
+                       if (pass == disabled) {
+                               PCIDBG(3,"PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+                                   r->start, r->end, r->flags, disabled, pass);
+                               pr = pci_find_parent_resource(dev, r);
+                               if (!pr || request_resource(pr, r) < 0) {
+                                       printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
+                                       /* We'll assign a new address later */
+                                       r->end -= r->start;
+                                       r->start = 0;
+                               }
+                       }
+               }
+               if (!pass) {
+                       r = &dev->resource[PCI_ROM_RESOURCE];
+                       if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+                               /* Turn the ROM off, leave the resource region, but keep it unregistered. */
+                               u32 reg;
+                               PCIDBG(3,"PCI: Switching off ROM of %s\n", dev->slot_name);
+                               r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+                               pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+                               pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+                       }
+               }
+       }
+}
+
+static void __init pcibios_assign_resources(void)
+{
+       struct pci_dev *dev;
+       int idx;
+       struct resource *r;
+
+       PCIDBG(2,"PCI: pcibios_assign_resources called\n");
+       pci_for_each_dev(dev) {
+               int class = dev->class >> 8;
+
+               /* Don't touch classless devices and host bridges */
+               if (!class || class == PCI_CLASS_BRIDGE_HOST)
+                       continue;
+
+               for(idx=0; idx<6; idx++) {
+                       r = &dev->resource[idx];
+
+                       /*
+                        *  Don't touch IDE controllers and I/O ports of video cards!
+                        */
+                       if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+                           (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+                               continue;
+
+                       /*
+                        *  We shall assign a new address to this resource, either because
+                        *  the BIOS forgot to do so or because we have decided the old
+                        *  address was unusable for some reason.
+                        */
+                       if (!r->start && r->end)
+                               pci_assign_resource(dev, idx);
+               }
+
+               if (pci_probe & PCI_ASSIGN_ROMS) {
+                       r = &dev->resource[PCI_ROM_RESOURCE];
+                       r->end -= r->start;
+                       r->start = 0;
+                       if (r->end)
+                               pci_assign_resource(dev, PCI_ROM_RESOURCE);
+               }
+       }
+}
+
+void __init pcibios_resource_survey(void)
+{
+       PCIDBG(1,"PCI: Allocating resources\n");
+       pcibios_allocate_bus_resources(&pci_root_buses);
+       pcibios_allocate_resources(0);
+       pcibios_allocate_resources(1);
+       pcibios_assign_resources();
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for(idx=0; idx<6; idx++) {
+               r = &dev->resource[idx];
+               if (!r->start && r->end) {
+                       printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               cmd |= PCI_COMMAND_MEMORY;
+       if (cmd != old_cmd) {
+               printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", dev->name, old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check and set
+ *  the latency timer as it may not be properly set.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+       u8 lat;
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       if (lat < 16)
+               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+       else if (lat > pcibios_max_latency)
+               lat = pcibios_max_latency;
+       else
+               return;
+       printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", dev->name, lat);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+/***************************************************************************************/
+/* 
+ *     IRQ functions 
+ */
+static u8 __init pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+{
+       /* no swizzling */
+       return PCI_SLOT(dev->devfn);
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int irq = -1;
+
+       /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+       irq = pcibios_map_platform_irq(slot,pin);
+       if( irq < 0 ) {
+           PCIDBG(3,"PCI: Error mapping IRQ on device %s\n", dev->name);
+               return irq;
+       }
+       
+       PCIDBG(2,"Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
+
+       return irq;
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+       PCIDBG(3,"PCI: Update IRQ for %s on irq %d\n", dev->name, irq);
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
index 972a352609c88a27ae0547a6ee13f1117414eb58..9bb13f35b77cc2fb50da15613a2cd32224566746 100644 (file)
@@ -141,6 +141,31 @@ static u32 __init r2p2(u32 num)
        return tmp;
 }
 
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+       int i;
+
+       /*
+        * PCI IDE controllers use non-standard I/O port decoding, respect it.
+        */
+       if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return;
+       printk("PCI: IDE base address fixup for %s\n", d->slot_name);
+       for(i=0; i<4; i++) {
+               struct resource *r = &d->resource[i];
+               if ((r->start & ~0x80) == 0x374) {
+                       r->start |= 2;
+                       r->end = r->start;
+               }
+       }
+}
+
+
+/* Add future fixups here... */
+struct pci_fixup pcibios_fixups[] = {
+       { PCI_FIXUP_HEADER,     PCI_ANY_ID,     PCI_ANY_ID,     pci_fixup_ide_bases },
+       { 0 }
+};
 
 int __init st40pci_init(unsigned memStart, unsigned memSize)
 {
@@ -234,6 +259,11 @@ int __init st40pci_init(unsigned memStart, unsigned memSize)
        return 1;
 }
 
+char * __init pcibios_setup(char *str)
+{
+       return str;
+}
+
 
 #define SET_CONFIG_BITS(bus,devfn,where)\
   (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0))
@@ -390,10 +420,14 @@ pcibios_fixup_pbus_ranges(struct pci_bus *bus,
        ranges->mem_end -= bus->resource[1]->start;
 }
 
-void __init st40_pcibios_init(void)
+void __init pcibios_init(void)
 {
        extern unsigned long memory_start, memory_end;
 
+       if (sh_mv.mv_init_pci != NULL) {
+               sh_mv.mv_init_pci();
+       }
+
        /* The pci subsytem needs to know where memory is and how much 
         * of it there is. I've simply made these globals. A better mechanism
         * is probably needed.
@@ -492,3 +526,23 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
        printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
+
+/*
+ *  If we set up a device for bus mastering, we need to check the latency
+ *  timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+       u8 lat;
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       if (lat < 16)
+               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+       else if (lat > pcibios_max_latency)
+               lat = pcibios_max_latency;
+       else
+               return;
+       printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
index a6586bd0d98fe11ce00bbc19da2a5b5f7ab360cc..d37d3960c5a98dbf4a1d7f13dc2b9c8e665d2629 100644 (file)
 #include <asm/io.h>
 #include <asm/rtc.h>
 
-/* RCR1 Bits */
-#define RCR1_CF                0x80    /* Carry Flag             */
-#define RCR1_CIE       0x10    /* Carry Interrupt Enable */
-#define RCR1_AIE       0x08    /* Alarm Interrupt Enable */
-#define RCR1_AF                0x01    /* Alarm Flag             */
-
-/* RCR2 Bits */
-#define RCR2_PEF       0x80    /* PEriodic interrupt Flag */
-#define RCR2_PESMASK   0x70    /* Periodic interrupt Set  */
-#define RCR2_RTCEN     0x08    /* ENable RTC              */
-#define RCR2_ADJ       0x04    /* ADJustment (30-second)  */
-#define RCR2_RESET     0x02    /* Reset bit               */
-#define RCR2_START     0x01    /* Start bit               */
-
-#if defined(__sh3__)
-/* SH-3 RTC */
-#define R64CNT         0xfffffec0
-#define RSECCNT        0xfffffec2
-#define RMINCNT        0xfffffec4
-#define RHRCNT         0xfffffec6
-#define RWKCNT         0xfffffec8
-#define RDAYCNT        0xfffffeca
-#define RMONCNT        0xfffffecc
-#define RYRCNT         0xfffffece
-#define RSECAR         0xfffffed0
-#define RMINAR         0xfffffed2
-#define RHRAR          0xfffffed4
-#define RWKAR          0xfffffed6
-#define RDAYAR         0xfffffed8
-#define RMONAR         0xfffffeda
-#define RCR1           0xfffffedc
-#define RCR2           0xfffffede
-
-#define RTC_BIT_INVERTED       0       /* No bug on SH7708, SH7709A */
-#elif defined(__SH4__)
-/* SH-4 RTC */
-#define R64CNT         0xffc80000
-#define RSECCNT        0xffc80004
-#define RMINCNT        0xffc80008
-#define RHRCNT         0xffc8000c
-#define RWKCNT         0xffc80010
-#define RDAYCNT        0xffc80014
-#define RMONCNT        0xffc80018
-#define RYRCNT         0xffc8001c  /* 16bit */
-#define RSECAR         0xffc80020
-#define RMINAR         0xffc80024
-#define RHRAR          0xffc80028
-#define RWKAR          0xffc8002c
-#define RDAYAR         0xffc80030
-#define RMONAR         0xffc80034
-#define RCR1           0xffc80038
-#define RCR2           0xffc8003c
-
-#define RTC_BIT_INVERTED       0x40    /* bug on SH7750, SH7750S */
-#endif
-
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
 #endif
index ba1337bec8dc051a8053ae5294b526201f0093ba..e3205801c1853b33d6639b53dedcc645c4765d2f 100644 (file)
@@ -521,6 +521,9 @@ int get_cpuinfo(char *buffer)
        
        PRINT_CLOCK("CPU", boot_cpu_data.cpu_clock);
        PRINT_CLOCK("Bus", boot_cpu_data.bus_clock);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+       PRINT_CLOCK("Memory", boot_cpu_data.memory_clock);
+#endif
        PRINT_CLOCK("Peripheral module", boot_cpu_data.module_clock);
 
        return p - buffer;
diff --git a/arch/sh/kernel/setup_bigsur.c b/arch/sh/kernel/setup_bigsur.c
new file mode 100644 (file)
index 0000000..d5bdb9a
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * 
+ * Setup and IRQ handling code for the HD64465 companion chip.
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc
+ *
+ * Derived from setup_hd64465.c which bore the message:
+ * Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc and
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * and setup_cqreek.c which bore message:
+ * Copyright (C) 2000  Niibe Yutaka
+ * 
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Setup and IRQ functions for a Hitachi Big Sur Evaluation Board.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#include <asm/io_bigsur.h>
+#include <asm/hd64465.h>
+#include <asm/bigsur.h>
+
+//#define BIGSUR_DEBUG 3
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...)       printk(args)
+#define DIPRINTK(n, args...)   if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif /* BIGSUR_DEBUG */
+
+#ifdef CONFIG_HD64465
+extern int hd64465_irq_demux(int irq);
+#endif /* CONFIG_HD64465 */
+
+
+/*===========================================================*/
+//             Big Sur CPLD IRQ Routines       
+/*===========================================================*/
+
+/* Level 1 IRQ routines */
+static void disable_bigsur_l1irq(unsigned int irq)
+{
+       unsigned long flags;
+       unsigned char mask;
+       unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+       unsigned char bit =  (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {    
+               DPRINTK("Disable L1 IRQ %d\n", irq);
+               DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", 
+                       mask_port, bit);
+               save_and_cli(flags);
+
+               /* Disable IRQ - set mask bit */
+               mask = inb(mask_port) | bit;
+               outb(mask, mask_port);
+               restore_flags(flags);
+               return;
+       }
+       DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq); 
+}
+
+static void enable_bigsur_l1irq(unsigned int irq)
+{
+       unsigned long flags;
+       unsigned char mask;
+       unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+       unsigned char bit =  (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {    
+               DPRINTK("Enable L1 IRQ %d\n", irq);
+               DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", 
+                       mask_port, bit);
+               save_and_cli(flags);
+               /* Enable L1 IRQ - clear mask bit */
+               mask = inb(mask_port) & ~bit;
+               outb(mask, mask_port);
+               restore_flags(flags);
+               return;
+       }
+       DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);  
+}
+
+
+/* Level 2 irq masks and registers for L2 decoding */
+/* Level2 bitmasks for each level 1 IRQ */
+const u32 bigsur_l2irq_mask[] = 
+    {0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03};
+/* Level2 to ISR[n] map for each level 1 IRQ */
+const u32 bigsur_l2irq_reg[]  = 
+    {   2,   2,   3,   3,   1,   2,   1,   0,   1,   1,   3,   2};
+/* Level2 to Level 1 IRQ map */
+const u32 bigsur_l2_l1_map[]  = 
+    {7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1};
+/* IRQ inactive level (high or low) */
+const u32 bigsur_l2_inactv_state[]  =   {0x00, 0xBE, 0xFC, 0xF7};
+/* CPLD external status and mask registers base and offsets */
+static const u32 isr_base = BIGSUR_IRQ0;
+static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1;
+static const u32 imr_base = BIGSUR_IMR0;
+static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
+
+#define REG_NUM(irq)  ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 )
+
+/* Level 2 IRQ routines */
+static void disable_bigsur_l2irq(unsigned int irq)
+{
+       unsigned long flags;
+       unsigned char mask;
+       unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+       unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+    if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+               DPRINTK("Disable L2 IRQ %d\n", irq);
+               DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", 
+                       mask_port, bit);
+               save_and_cli(flags);
+
+               /* Disable L2 IRQ - set mask bit */
+               mask = inb(mask_port) | bit;
+               outb(mask, mask_port);
+               restore_flags(flags);
+               return;
+       }
+       DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq); 
+}
+
+static void enable_bigsur_l2irq(unsigned int irq)
+{
+       unsigned long flags;
+       unsigned char mask;
+       unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+       unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+    if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+               DPRINTK("Enable L2 IRQ %d\n", irq);
+               DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", 
+                       mask_port, bit);
+               save_and_cli(flags);
+
+               /* Enable L2 IRQ - clear mask bit */
+               mask = inb(mask_port) & ~bit;
+               outb(mask, mask_port);
+               restore_flags(flags);
+               return;
+       }
+       DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+}
+
+static void mask_and_ack_bigsur(unsigned int irq)
+{
+       DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)      
+               disable_bigsur_l1irq(irq);
+       else
+               disable_bigsur_l2irq(irq);
+}
+
+static void end_bigsur_irq(unsigned int irq)
+{
+       DPRINTK("end_bigsur_irq IRQ %d\n", irq);
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)      
+               enable_bigsur_l1irq(irq);
+       else
+               enable_bigsur_l2irq(irq);
+}
+
+static unsigned int startup_bigsur_irq(unsigned int irq)
+{ 
+       u8 mask;
+       u32 reg;
+
+       DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
+
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+               /* Enable the L1 IRQ */ 
+               enable_bigsur_l1irq(irq);
+               /* Enable all L2 IRQs in this L1 IRQ */
+               mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]);
+               reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset;
+               mask &= inb(reg);
+               outb(mask,reg); 
+               DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg));
+       }
+       else {
+               /* Enable the L2 IRQ - clear mask bit */
+               enable_bigsur_l2irq(irq);
+               /* Enable the L1 bit masking this L2 IRQ */
+               enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]);
+               DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n",
+                       bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq);
+       }
+       return 0;
+}
+
+static void shutdown_bigsur_irq(unsigned int irq)
+{
+       DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)      
+               disable_bigsur_l1irq(irq);
+       else
+               disable_bigsur_l2irq(irq);
+}
+
+/* Define the IRQ structures for the L1 and L2 IRQ types */
+static struct hw_interrupt_type bigsur_l1irq_type = {
+       "BigSur-CPLD-Level1-IRQ",
+       startup_bigsur_irq,
+       shutdown_bigsur_irq,
+       enable_bigsur_l1irq,
+       disable_bigsur_l1irq,
+       mask_and_ack_bigsur,
+       end_bigsur_irq
+};
+
+static struct hw_interrupt_type bigsur_l2irq_type = {
+       "BigSur-CPLD-Level2-IRQ",
+       startup_bigsur_irq,
+       shutdown_bigsur_irq,
+       enable_bigsur_l2irq,
+       disable_bigsur_l2irq,
+       mask_and_ack_bigsur,
+       end_bigsur_irq
+};
+
+
+static void make_bigsur_l1isr(unsigned int irq) {
+
+       /* sanity check first */
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {    
+               /* save the handler in the main description table */
+               irq_desc[irq].handler = &bigsur_l1irq_type;
+               irq_desc[irq].status = IRQ_DISABLED;
+               irq_desc[irq].action = 0;
+               irq_desc[irq].depth = 1;
+
+               disable_bigsur_l1irq(irq);
+               return;
+       }
+       DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
+       return;
+} 
+
+static void make_bigsur_l2isr(unsigned int irq) {
+
+       /* sanity check first */
+       if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {      
+               /* save the handler in the main description table */
+               irq_desc[irq].handler = &bigsur_l2irq_type;
+               irq_desc[irq].status = IRQ_DISABLED;
+               irq_desc[irq].action = 0;
+               irq_desc[irq].depth = 1;
+
+               disable_bigsur_l2irq(irq);
+               return;
+       }
+       DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
+       return;
+} 
+
+/* The IRQ's will be decoded as follows: 
+ * If a level 2 handler exists and there is an unmasked active
+ * IRQ, the 2nd level handler will be called.
+ * If a level 2 handler does not exist for the active IRQ
+ * the 1st level handler will be called.
+ */ 
+
+int bigsur_irq_demux(int irq)
+{
+       int dmux_irq = irq;
+       u8 mask, actv_irqs;
+       u32 reg_num;
+
+       DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq);
+       /* decode the 1st level IRQ */
+       if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+               /* Get corresponding L2 ISR bitmask and ISR number */
+               mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW];
+               reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW];
+               /* find the active IRQ's (XOR with inactive level)*/
+               actv_irqs = inb(isr_base-reg_num*isr_offset) ^ 
+                                       bigsur_l2_inactv_state[reg_num];
+               /* decode active IRQ's */
+               actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset));
+               /* if NEZ then we have an active L2 IRQ */
+               if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW;     
+               /* if no 2nd level IRQ action, but has 1st level, use 1st level handler */
+               if(!irq_desc[dmux_irq].action && irq_desc[irq].action) 
+                       dmux_irq = irq;
+               DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n", 
+                       irq, dmux_irq, mask, reg_num);
+       }
+#ifdef CONFIG_HD64465
+       dmux_irq = hd64465_irq_demux(dmux_irq);
+#endif /* CONFIG_HD64465 */
+       DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq);
+               
+       return dmux_irq;
+}
+
+/*===========================================================*/
+//             Big Sur Init Routines   
+/*===========================================================*/
+void __init init_bigsur_IRQ(void)
+{
+       int i;
+
+       if (!MACH_BIGSUR) return;
+
+       /* Create ISR's for Big Sur CPLD IRQ's */
+       /*==============================================================*/
+       for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++) 
+               make_bigsur_l1isr(i);
+
+       printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n",
+               BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH);
+
+       for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++) 
+               make_bigsur_l2isr(i);
+
+       printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n",
+               BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH);
+
+}
+
+int __init setup_bigsur(void)
+{
+       static int done = 0; /* run this only once */
+
+       if (!MACH_BIGSUR || done) return 0;
+       done = 1;
+
+       /* Mask all 2nd level IRQ's */
+       outb(-1,BIGSUR_IMR0);
+       outb(-1,BIGSUR_IMR1);
+       outb(-1,BIGSUR_IMR2);
+       outb(-1,BIGSUR_IMR3);
+
+       /* Mask 1st level interrupts */
+       outb(-1,BIGSUR_IRLMR0);
+       outb(-1,BIGSUR_IRLMR1);
+
+#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL) 
+       /* remap IO ports for first ISA serial port to HD64465 UART */
+       bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
+#endif /* CONFIG_HD64465 && CONFIG_SERIAL */
+       /* TODO: setup IDE registers */
+       bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8);
+       /* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */
+       bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0);
+       /* set page to 1 */
+       outw(1, BIGSUR_ETHR+0xe);
+       /* set the IO port to BIGSUR_ETHER_IOPORT */
+       outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
+
+    return 0;
+}
+
+module_init(setup_bigsur);
index 32e57bbb86acfbcb67a10edbe83ba634b436d653..326a62d3f37d569ed7878d61054bb7f4d83c10ab 100644 (file)
@@ -1,5 +1,15 @@
-/*
- *     $Id: setup_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+/* arch/sh/kernel/setup_dc.c
+ *
+ * Hardware support for the Sega Dreamcast.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ * 
+ * This file originally bore the message:
+ *     $Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp $
  *     SEGA Dreamcast support
  */
 
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <linux/pci.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/dc_sysasic.h>
 
-#define        GAPSPCI_REGS            0x01001400
-#define GAPSPCI_DMA_BASE       0x01840000
-#define GAPSPCI_DMA_SIZE       32768
-#define GAPSPCI_BBA_CONFIG     0x01001600
+int __init gapspci_init(void);
 
-#define        GAPSPCI_IRQ             11
-#define        GAPSPCI_INTC            0x005f6924
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 
-static int gapspci_dma_used;
+/* Dreamcast System ASIC Hardware Events -
+   The Dreamcast's System ASIC (located on the PowerVR2 chip) is responsible
+   for receiving hardware events from system peripherals and triggering an
+   SH7750 IRQ.  Hardware events can trigger IRQs 13, 11, or 9 depending on
+   which bits are set in the Event Mask Registers (EMRs).  When a hardware
+   event is triggered, it's corresponding bit in the Event Status Registers
+   (ESRs) is set, and that bit should be rewritten to the ESR to acknowledge
+   that event.
 
-static struct pci_bus *pci_root_bus;
+   There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908.  Event
+   types can be found in include/asm-sh/dc_sysasic.h.  There are three groups
+   of EMRs that parallel the ESRs.  Each EMR group corresponds to an IRQ, so
+   0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
+   IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
 
-static void disable_gapspci_irq(unsigned int irq)
-{
-       unsigned long flags;
-       unsigned long intc;
-
-       save_and_cli(flags);
-       intc = inl(GAPSPCI_INTC);
-       intc &= ~(1<<3);
-       outl(intc, GAPSPCI_INTC);
-       restore_flags(flags);
-}
+   In the kernel, these events are mapped to virtual IRQs so that drivers can
+   respond to them as they would a normal interrupt.  In order to keep this
+   mapping simple, the events are mapped as:
+
+   6900/6910 - Events  0-31, IRQ 13
+   6904/6924 - Events 32-63, IRQ 11
+   6908/6938 - Events 64-95, IRQ  9
+
+*/
+
+#define ESR_BASE 0x005f6900    /* Base event status register */
+#define EMR_BASE 0x005f6910    /* Base event mask register */
+
+/* Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
+   1 = 0x6920, 2 = 0x6930; also determine the event offset */
+#define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32)
+
+/* Return the hardware event's bit positon within the EMR/ESR */
+#define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31)
 
+/* For each of these *_irq routines, the IRQ passed in is the virtual IRQ
+   (logically mapped to the corresponding bit for the hardware event). */
 
-static void enable_gapspci_irq(unsigned int irq)
+/* Disable the hardware event by masking its bit in its EMR */
+static inline void disable_systemasic_irq(unsigned int irq)
 {
-       unsigned long flags;
-       unsigned long intc;
-
-       save_and_cli(flags);
-       intc = inl(GAPSPCI_INTC);
-       intc |= (1<<3);
-       outl(intc, GAPSPCI_INTC);
-       restore_flags(flags);
+       __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+       __u32 mask;
+       mask = inl(emr);
+       mask &= ~(1 << EVENT_BIT(irq));
+       outl(mask, emr);
 }
 
-
-static void mask_and_ack_gapspci_irq(unsigned int irq)
+/* Enable the hardware event by setting its bit in its EMR */
+static inline void enable_systemasic_irq(unsigned int irq)
 {
-       unsigned long flags;
-       unsigned long intc;
-
-       save_and_cli(flags);
-       intc = inl(GAPSPCI_INTC);
-       intc &= ~(1<<3);
-       outl(intc, GAPSPCI_INTC);
-       restore_flags(flags);
+       __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+       __u32 mask;
+       mask = inl(emr);
+       mask |= (1 << EVENT_BIT(irq));
+       outl(mask, emr);
 }
 
+/* Acknowledge a hardware event by writing its bit back to its ESR */
+static void ack_systemasic_irq(unsigned int irq)
+{
+       __u32 esr = ESR_BASE + (LEVEL(irq) << 2);
+       disable_systemasic_irq(irq);
+       outl((1 << EVENT_BIT(irq)), esr);
+}
 
-static void end_gapspci_irq(unsigned int irq)
+/* After a IRQ has been ack'd and responded to, it needs to be renabled */
+static void end_systemasic_irq(unsigned int irq)
 {
-       enable_gapspci_irq(irq);
+       enable_systemasic_irq(irq);
 }
 
+static unsigned int startup_systemasic_irq(unsigned int irq)
+{
+       enable_systemasic_irq(irq);
 
-static unsigned int startup_gapspci_irq(unsigned int irq)
-{ 
-       enable_gapspci_irq(irq);
        return 0;
 }
 
-
-static void shutdown_gapspci_irq(unsigned int irq)
+static void shutdown_systemasic_irq(unsigned int irq)
 {
-       disable_gapspci_irq(irq);
+       disable_systemasic_irq(irq);
 }
 
-
-static struct hw_interrupt_type gapspci_irq_type = {
-       "GAPSPCI-IRQ",
-       startup_gapspci_irq,
-       shutdown_gapspci_irq,
-       enable_gapspci_irq,
-       disable_gapspci_irq,
-       mask_and_ack_gapspci_irq,
-       end_gapspci_irq
+static struct hw_interrupt_type systemasic_int = {
+       typename:       "System ASIC",
+       startup:        startup_systemasic_irq,
+       shutdown:       shutdown_systemasic_irq,
+       enable:         enable_systemasic_irq,
+       disable:        disable_systemasic_irq,
+       ack:            ack_systemasic_irq,
+       end:            end_systemasic_irq,
 };
 
+/*
+ * Map the hardware event indicated by the processor IRQ to a virtual IRQ.
+ */
+int systemasic_irq_demux(int irq)
+{
+       __u32 emr, esr, status, level;
+       __u32 j, bit;
+
+       switch (irq) {
+               case 13:
+                       level = 0;
+                       break;
+               case 11:
+                       level = 1;
+                       break;
+               case  9:
+                       level = 2;
+                       break;
+               default:
+                       return irq;
+       }
+       emr = EMR_BASE + (level << 4) + (level << 2);
+       esr = ESR_BASE + (level << 2);
+
+       /* Mask the ESR to filter any spurious, unwanted interrtupts */
+       status = inl(esr);
+       status &= inl(emr);
+
+       /* Now scan and find the first set bit as the event to map */
+       for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
+               if (status & bit) {
+                       irq = HW_EVENT_IRQ_BASE + j + (level << 5);
+                       return irq;
+               }
+       }
 
-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
-{
-       return PCI_SLOT(dev->devfn);
-}
-
-static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-       return GAPSPCI_IRQ;
+       /* Not reached */
+       return irq;
 }
 
 int __init setup_dreamcast(void)
 {
+       int i;
+
+       /* Mask all hardware events */
+       /* XXX */
+
+       /* Acknowledge any previous events */
+       /* XXX */
+
+       /* Assign all virtual IRQs to the System ASIC int. handler */
+       for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
+               irq_desc[i].handler = &systemasic_int;
+
+#ifdef CONFIG_PCI
        gapspci_init();
+#endif
 
        printk(KERN_INFO "SEGA Dreamcast support.\n");
 #if 0
@@ -130,230 +202,3 @@ int __init setup_dreamcast(void)
 #endif
        return 0;
 }
-
-
-/*
- *     Dreamcast PCI: Supports SEGA Broadband Adaptor only.
- */
-
-#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
-
-static int gapspci_read_config_byte(struct pci_dev *dev, int where,
-                                    u8 * val)
-{
-       if (BBA_SELECTED(dev))
-               *val = inb(GAPSPCI_BBA_CONFIG+where);
-       else
-                *val = 0xff;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_read_config_word(struct pci_dev *dev, int where,
-                                    u16 * val)
-{
-        if (BBA_SELECTED(dev))
-               *val = inw(GAPSPCI_BBA_CONFIG+where);
-       else
-                *val = 0xffff;
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_read_config_dword(struct pci_dev *dev, int where,
-                                     u32 * val)
-{
-        if (BBA_SELECTED(dev))
-               *val = inl(GAPSPCI_BBA_CONFIG+where);
-       else
-                *val = 0xffffffff;
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_write_config_byte(struct pci_dev *dev, int where,
-                                     u8 val)
-{
-        if (BBA_SELECTED(dev))
-               outb(val, GAPSPCI_BBA_CONFIG+where);
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int gapspci_write_config_word(struct pci_dev *dev, int where,
-                                     u16 val)
-{
-        if (BBA_SELECTED(dev))
-               outw(val, GAPSPCI_BBA_CONFIG+where);
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_write_config_dword(struct pci_dev *dev, int where,
-                                      u32 val)
-{
-        if (BBA_SELECTED(dev))
-               outl(val, GAPSPCI_BBA_CONFIG+where);
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_config_ops = {
-        gapspci_read_config_byte,
-        gapspci_read_config_word,
-        gapspci_read_config_dword,
-        gapspci_write_config_byte,
-        gapspci_write_config_word,
-        gapspci_write_config_dword
-};
-
-
-void pcibios_align_resource(void *data, struct resource *res,
-                           unsigned long size)
-{
-}
-
-
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-}
-
-
-void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-                            struct resource *res, int resource)
-{
-}
-
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-
-       u16 cmd, old_cmd;
-       int idx;
-       struct resource *r;
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
-       for (idx = 0; idx < 6; idx++) {
-               r = dev->resource + idx;
-               if (!r->start && r->end) {
-                       printk(KERN_ERR
-                              "PCI: Device %s not available because"
-                              " of resource collisions\n",
-                              dev->slot_name);
-                       return -EINVAL;
-               }
-               if (r->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               if (r->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-       }
-       if (cmd != old_cmd) {
-               printk("PCI: enabling device %s (%04x -> %04x)\n",
-                      dev->slot_name, old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-       }
-       return 0;
-
-}
-
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-                          dma_addr_t * dma_handle)
-{
-       unsigned long buf;
-
-       if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
-               return NULL;
-
-       buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
-
-       gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
-       
-       printk("pci_alloc_consistent: %d bytes at 0x%08x\n", size, buf);
-
-       *dma_handle = (dma_addr_t)buf;
-
-       return (void *)P2SEGADDR(buf);
-}
-
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-                        void *vaddr, dma_addr_t dma_handle)
-{
-}
-
-
-void __init
-pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
-{
-}                                                                                
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-       struct list_head *ln;
-       struct pci_dev *dev;
-
-       for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-               dev = pci_dev_b(ln);
-               if (!BBA_SELECTED(dev)) continue;
-
-               printk("PCI: MMIO fixup to %s\n", dev->name);
-               dev->resource[1].start=0x01001700;
-               dev->resource[1].end=0x010017ff;
-       }
-}
-
-
-void __init dreamcast_pcibios_init(void)
-{
-       pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
-       /* pci_assign_unassigned_resources(); */
-       pci_fixup_irqs(no_swizzle, map_od_irq);
-}
-
-
-static __init int gapspci_init(void)
-{
-       int i;
-       char idbuf[16];
-
-       for(i=0; i<16; i++)
-               idbuf[i]=inb(GAPSPCI_REGS+i);
-
-       if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
-               return -1;
-
-       outl(0x5a14a501, GAPSPCI_REGS+0x18);
-
-       for(i=0; i<1000000; i++);
-
-       if(inl(GAPSPCI_REGS+0x18)!=1)
-               return -1;
-
-       outl(0x01000000, GAPSPCI_REGS+0x20);
-       outl(0x01000000, GAPSPCI_REGS+0x24);
-
-       outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
-       outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
-
-       outl(1, GAPSPCI_REGS+0x14);
-       outl(1, GAPSPCI_REGS+0x34);
-
-       gapspci_dma_used=0;
-
-       /*  */
-       irq_desc[GAPSPCI_IRQ].handler = &gapspci_irq_type;
-
-       /* Setting Broadband Adapter */
-       outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
-       outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
-       outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
-       outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
-       outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
-       outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
-       outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
-
-       return 0;
-}
diff --git a/arch/sh/kernel/setup_od.c b/arch/sh/kernel/setup_od.c
deleted file mode 100644 (file)
index f605bd2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* $Id: setup_od.c,v 1.1 2000/06/14 09:35:59 stuart_menefy Exp $
- *
- * arch/sh/kernel/setup_od.c
- *
- * Copyright (C) 2000  Stuart Menefy
- *
- * STMicroelectronics Overdrive Support.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-/*
- * Initialize the board
- */
-int __init setup_od(void)
-{
-       /* Enable RS232 receive buffers */
-       volatile int* p = (volatile int*)0xa3000000;
-
-#if defined(CONFIG_SH_ORION)
-       *p=1;
-#elif defined(CONFIG_SH_OVERDRIVE)
-       *p=0x1e;
-#else
-#error Illegal configuration
-#endif
-
-       printk(KERN_INFO "STMicroelectronics Overdrive Setup...done\n");
-       return 0;
-}
-
-module_init(setup_od);
diff --git a/arch/sh/kernel/setup_sh2000.c b/arch/sh/kernel/setup_sh2000.c
new file mode 100644 (file)
index 0000000..ce07700
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * linux/arch/sh/kernel/setup_sh2000.c
+ *
+ * Copyright (C) 2001  SUGIOKA Tochinobu
+ *
+ * SH-2000 Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/rtc.h>
+
+#define CF_CIS_BASE    0xb4200000
+
+#define PORT_PECR      0xa4000108
+#define PORT_PHCR      0xa400010E
+#define        PORT_ICR1       0xa4000010
+#define        PORT_IRR0       0xa4000004
+
+/*
+ * Initialize the board
+ */
+int __init setup_sh2000(void)
+{
+       /* XXX: RTC setting comes here */
+
+       /* These should be done by BIOS/IPL ... */
+       /* Enable nCE2A, nCE2B output */
+       ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR);
+       /* Enable the Compact Flash card, and set the level interrupt */
+       ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
+       /* Enable interrupt */
+       ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR);
+       ctrl_outw(1, PORT_ICR1);
+       ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0);
+       printk(KERN_INFO "SH-2000 Setup...done\n");
+       return 0;
+}
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh2000 __initmv = {
+       mv_name:                "sh2000",
+
+       mv_nr_irqs:             80,
+
+       mv_inb:                 generic_inb,
+       mv_inw:                 generic_inw,
+       mv_inl:                 generic_inl,
+       mv_outb:                generic_outb,
+       mv_outw:                generic_outw,
+       mv_outl:                generic_outl,
+
+       mv_inb_p:               generic_inb_p,
+       mv_inw_p:               generic_inw_p,
+       mv_inl_p:               generic_inl_p,
+       mv_outb_p:              generic_outb_p,
+       mv_outw_p:              generic_outw_p,
+       mv_outl_p:              generic_outl_p,
+
+       mv_insb:                generic_insb,
+       mv_insw:                generic_insw,
+       mv_insl:                generic_insl,
+       mv_outsb:               generic_outsb,
+       mv_outsw:               generic_outsw,
+       mv_outsl:               generic_outsl,
+
+       mv_readb:               generic_readb,
+       mv_readw:               generic_readw,
+       mv_readl:               generic_readl,
+       mv_writeb:              generic_writeb,
+       mv_writew:              generic_writew,
+       mv_writel:              generic_writel,
+
+       mv_init_arch:           setup_sh2000,
+
+       mv_isa_port2addr:       sh2000_isa_port2addr,
+
+       mv_ioremap:             generic_ioremap,
+       mv_iounmap:             generic_iounmap,
+
+       mv_rtc_gettimeofday:    sh_rtc_gettimeofday,
+       mv_rtc_settimeofday:    sh_rtc_settimeofday,
+
+       mv_hw_sh2000:           1,
+};
+ALIAS_MV(sh2000)
index eb56b61036a4964a39f9cc40ddf18fce24042fb8..6fda83eb359fabcf241d7bf9c77036464e9cca26 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/hardirq.h>
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
+#include <asm/pci.h>
 #include <linux/irq.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
@@ -44,14 +45,25 @@ EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strncat);
 
+/* PCI exports */
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pcibios_penalize_isa_irq);
+#endif
+
 /* mem exports */
 EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memcpy_toio);
 EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memset_io);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memcmp);
 
@@ -63,20 +75,32 @@ EXPORT_SYMBOL(boot_cpu_data);
 
 EXPORT_SYMBOL(get_vm_area);
 
+/* semaphore exports */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__const_udelay);
+
 #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name)
  
 /* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrdi3);
+DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstr);
 
 #ifdef __SH4__
  
 DECLARE_EXPORT(__movstr_i4_even);
 DECLARE_EXPORT(__movstr_i4_odd);
-DECLARE_EXPORT(__ashrdi3);
-DECLARE_EXPORT(__ashldi3);
 
 /* needed by some modules */
+EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(flush_cache_range);
 EXPORT_SYMBOL(flush_dcache_page);
 #endif
 EXPORT_SYMBOL(flush_tlb_page);
index 8ee4800e280ac8c1a1eb1ac017dd05958d3341f9..ea428d7e3a346fc5b224bb868bb8210d02e36172 100644 (file)
 #define CCN_PVR_CHIP_MASK  0xff
 #define CCN_PVR_CHIP_ST40STB1 0x4
 
-#endif
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+#define CLOCKGEN_MEMCLKCR 0xbb040038
+#define MEMCLKCR_RATIO_MASK 0x7
+#endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */
+#endif /* __sh3__ or __SH4__ */
 
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
@@ -285,6 +289,9 @@ static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NUL
 void __init time_init(void)
 {
        unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+       unsigned int memory_clock;
+#endif
        unsigned int timer_freq;
        unsigned short frqcr, ifc, pfc, bfc;
        unsigned long interval;
@@ -335,23 +342,35 @@ void __init time_init(void)
                { 0x123, {{1,4}, {1,4}, {1,8}}},
                { 0x16C, {{1,4}, {1,8}, {1,8}}},
        };
+
+       struct memclk_data {
+               unsigned char multiplier;
+               unsigned char divisor;
+       };
+       static struct memclk_data st40_memclk_table[8] = {
+               {1,1},  // 000
+               {1,2},  // 001
+               {1,3},  // 010
+               {2,3},  // 011
+               {1,4},  // 100
+               {1,6},  // 101
+               {1,8},  // 110
+               {1,8}   // 111
+       };
 #endif
 #endif
 
-#if defined(CONFIG_SH_DREAMCAST)
-       xtime.tv_sec = 0;
-       xtime.tv_usec = 0;
-#else
-       rtc_gettimeofday(&xtime);
-#endif
+       if (MACH_DREAMCAST)
+               xtime.tv_sec = xtime.tv_usec = 0;
+       else
+               rtc_gettimeofday(&xtime);
 
        setup_irq(TIMER_IRQ, &irq0);
 
-#if defined(CONFIG_SH_DREAMCAST)
-       timer_freq = 50*1000*1000/4;
-#else
-       timer_freq = get_timer_frequency();
-#endif
+       if (MACH_DREAMCAST)
+               timer_freq = 50*1000*1000/4;
+       else
+               timer_freq = get_timer_frequency();
 
        module_clock = timer_freq * 4;
 
@@ -386,6 +405,8 @@ void __init time_init(void)
                        /* Unfortunatly the STB1 FRQCR values are different from the 7750 ones */
                        struct frqcr_data *d;
                        int a;
+                       unsigned long memclkcr;
+                       struct memclk_data *e;
 
                        for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) {
                                d = &st40_frqcr_table[a];
@@ -397,13 +418,18 @@ void __init time_init(void)
                                printk("ERROR: Unrecognised FRQCR value, using default multipliers\n");
                        }
 
-                       printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Periph: %d/%d\n",
+                       memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR);
+                       e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK];
+
+                       printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n",
                               d->factor[0].multiplier, d->factor[0].divisor,
                               d->factor[1].multiplier, d->factor[1].divisor,
+                              e->multiplier,           e->divisor,
                               d->factor[2].multiplier, d->factor[2].divisor);
                        
                        master_clock = module_clock * d->factor[2].divisor    / d->factor[2].multiplier;
                        bus_clock    = master_clock * d->factor[1].multiplier / d->factor[1].divisor;
+                       memory_clock = master_clock * e->multiplier           / e->divisor;
                        cpu_clock    = master_clock * d->factor[0].multiplier / d->factor[0].divisor;
                        goto skip_calc;
                } else
@@ -418,11 +444,17 @@ void __init time_init(void)
        master_clock = module_clock * pfc;
        bus_clock = master_clock / bfc;
        cpu_clock = master_clock / ifc;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
  skip_calc:
+#endif
        printk("CPU clock: %d.%02dMHz\n",
               (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
        printk("Bus clock: %d.%02dMHz\n",
               (bus_clock/1000000), (bus_clock % 1000000)/10000);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+       printk("Memory clock: %d.%02dMHz\n",
+              (memory_clock/1000000), (memory_clock % 1000000)/10000);
+#endif
        printk("Module clock: %d.%02dMHz\n",
               (module_clock/1000000), (module_clock % 1000000)/10000);
        interval = (module_clock/4 + HZ/2) / HZ;
@@ -432,6 +464,9 @@ void __init time_init(void)
        current_cpu_data.cpu_clock    = cpu_clock;
        current_cpu_data.master_clock = master_clock;
        current_cpu_data.bus_clock    = bus_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+       current_cpu_data.memory_clock = memory_clock;
+#endif
        current_cpu_data.module_clock = module_clock;
 
        /* Start TMU0 */
index 97b0a7f945f624e0908aab3a63cfd36ffeeca00f..8501d7ef09c48a0c693d803c38a4ea97da85e160 100644 (file)
@@ -151,7 +151,8 @@ detect_cpu_and_cache_system(void)
 #elif defined(__SH4__)
 #ifdef CONFIG_CPU_SUBTYPE_ST40STB1
        cpu_data->type = CPU_ST40STB1;
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751)
        cpu_data->type = CPU_SH7750;
 #else
 #error Unknown SH4 CPU type
index 7d75f92b53c9af9dad9e5f0674df102c72e132fd..f554a571236165c2324f92e2fddff3ed671b86fd 100644 (file)
@@ -281,11 +281,12 @@ void update_mmu_cache(struct vm_area_struct * vma,
 {
        unsigned long flags;
        unsigned long pteval;
-       unsigned long pteaddr;
+       unsigned long vpn;
+#if defined(__SH4__)
        unsigned long ptea;
+#endif
 
        save_and_cli(flags);
-
 #if defined(__SH4__)
        if (pte_shared(pte)) {
                struct page *pg;
@@ -305,13 +306,13 @@ void update_mmu_cache(struct vm_area_struct * vma,
        }
 
        /* Set PTEH register */
-       pteaddr = (address & MMU_VPN_MASK) | get_asid();
-       ctrl_outl(pteaddr, MMU_PTEH);
+       vpn = (address & MMU_VPN_MASK) | get_asid();
+       ctrl_outl(vpn, MMU_PTEH);
 
-       /* Set PTEA register */
-       /* TODO: make this look less hacky */
        pteval = pte_val(pte);
 #if defined(__SH4__)
+       /* Set PTEA register */
+       /* TODO: make this look less hacky */
        ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
        ctrl_outl(ptea, MMU_PTEA);
 #endif
@@ -341,9 +342,9 @@ static void __flush_tlb_page(unsigned long asid, unsigned long page)
        data = (page & 0xfffe0000) | asid; /* VALID bit is off */
        ctrl_outl(data, addr);
 #elif defined(__SH4__)
-       jump_to_P2();
        addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
        data = page | asid; /* VALID bit is off */
+       jump_to_P2();
        ctrl_outl(data, addr);
        back_to_P1();
 #endif
@@ -352,27 +353,34 @@ static void __flush_tlb_page(unsigned long asid, unsigned long page)
 #if defined(__SH4__)
 static void __flush_tlb_phys(unsigned long phys)
 {
-       int i;
-       unsigned long addr, data;
+       unsigned long addr, data, pte;
 
-       jump_to_P2();
-       for (i = 0; i < MMU_UTLB_ENTRIES; i++) {
-               addr = MMU_UTLB_DATA_ARRAY | (i<<MMU_U_ENTRY_SHIFT);
+       pte = phys | MMU_UTLB_VALID;
+       for (addr = MMU_UTLB_DATA_ARRAY;
+            addr < MMU_UTLB_DATA_ARRAY+(MMU_UTLB_ENTRIES<<MMU_U_ENTRY_SHIFT);
+            addr += (1<<MMU_U_ENTRY_SHIFT)) {
                data = ctrl_inl(addr);
-               if ((data & MMU_UTLB_VALID) && (data&PAGE_MASK) == phys) {
+               if ((data & (MMU_UTLB_VALID|PAGE_MASK)) == pte) {
                        data &= ~MMU_UTLB_VALID;
+                       jump_to_P2();
                        ctrl_outl(data, addr);
+                       back_to_P1();
+                       break;
                }
        }
-       for (i = 0; i < MMU_ITLB_ENTRIES; i++) {
-               addr = MMU_ITLB_DATA_ARRAY | (i<<MMU_I_ENTRY_SHIFT);
+       pte = phys | MMU_ITLB_VALID;
+       for (addr = MMU_ITLB_DATA_ARRAY;
+            addr < MMU_ITLB_DATA_ARRAY+(MMU_ITLB_ENTRIES<<MMU_I_ENTRY_SHIFT);
+            addr += (1<<MMU_I_ENTRY_SHIFT)) {
                data = ctrl_inl(addr);
-               if ((data & MMU_ITLB_VALID) && (data&PAGE_MASK) == phys) {
+               if ((data & (MMU_ITLB_VALID|PAGE_MASK)) == pte) {
                        data &= ~MMU_ITLB_VALID;
+                       jump_to_P2();
                        ctrl_outl(data, addr);
+                       back_to_P1();
+                       break;
                }
        }
-       back_to_P1();
 }
 #endif
 
index 33899979812abb1e1c541a271b46e845c6636453..e6a8d9bee07ba21fb7b78eb31f729c33a93e678a 100644 (file)
@@ -100,7 +100,7 @@ void show_mem(void)
 extern char _text, _etext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
-pgd_t swapper_pg_dir[1024];
+pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 /* It'd be good if these lines were in the standard header file. */
 #define START_PFN      (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
@@ -120,7 +120,7 @@ void __init paging_init(void)
        /* We don't need kernel mapping as hardware support that. */
        pg_dir = swapper_pg_dir;
 
-       for (i=0; i < USER_PTRS_PER_PGD*2; i++)
+       for (i=0; i < PTRS_PER_PGD; i++)
                pgd_val(pg_dir[i]) = 0;
 
        /* Enable MMU */
diff --git a/arch/sh/stboards/Makefile b/arch/sh/stboards/Makefile
new file mode 100644 (file)
index 0000000..a14ecc9
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Makefile for STMicroelectronics board specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+all: stboards.o
+O_TARGET := stboards.o
+obj-y := irq.o setup.o mach.o led.o
+
+clean:
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/sh/stboards/harp.h b/arch/sh/stboards/harp.h
new file mode 100644 (file)
index 0000000..b2fbcfa
--- /dev/null
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Defintions applicable to the STMicroelectronics ST40STB1 HARP and
+ * compatible boards.
+ */
+
+#if defined(CONFIG_SH_STB1_HARP)
+
+#define EPLD_BASE     0xa0800000
+
+#define EPLD_LED      (EPLD_BASE+0x000c0000)
+#define EPLD_INTSTAT0 (EPLD_BASE+0x00200000)
+#define EPLD_INTSTAT1 (EPLD_BASE+0x00240000)
+#define EPLD_INTMASK0 (EPLD_BASE+0x00280000)
+#define EPLD_INTMASK1 (EPLD_BASE+0x002c0000)
+#define EPLD_PAGEADDR (EPLD_BASE+0x00300000)
+#define EPLD_REVID1   (EPLD_BASE+0x00380000)
+#define EPLD_REVID2   (EPLD_BASE+0x003c0000)
+
+#define EPLD_LED_ON  1
+#define EPLD_LED_OFF 0
+
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+
+#define EPLD_BASE     0xa7000000
+
+#define EPLD_REVID    (EPLD_BASE+0x00000000)
+#define EPLD_LED      (EPLD_BASE+0x00040000)
+#define EPLD_INTMASK0 (EPLD_BASE+0x001c0000)
+#define EPLD_INTMASK1 (EPLD_BASE+0x00200000)
+#define EPLD_INTSTAT0 (EPLD_BASE+0x00240000)
+#define EPLD_INTSTAT1 (EPLD_BASE+0x00280000)
+
+#define EPLD_LED_ON  0
+#define EPLD_LED_OFF 1
+
+#else
+#error Unknown board
+#endif
diff --git a/arch/sh/stboards/irq.c b/arch/sh/stboards/irq.c
new file mode 100644 (file)
index 0000000..46e3ba9
--- /dev/null
@@ -0,0 +1,149 @@
+/* 
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Looks after interrupts on the HARP board.
+ *
+ * Bases on the IPR irq system
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "harp.h"
+
+
+#define NUM_EXTERNAL_IRQS 16
+
+// Early versions of the STB1 Overdrive required this nasty frig
+//#define INVERT_INTMASK_WRITES
+
+static void enable_harp_irq(unsigned int irq);
+static void disable_harp_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_harp_irq disable_harp_irq
+
+static void mask_and_ack_harp(unsigned int);
+static void end_harp_irq(unsigned int irq);
+
+static unsigned int startup_harp_irq(unsigned int irq)
+{
+       enable_harp_irq(irq);
+       return 0;               /* never anything pending */
+}
+
+static struct hw_interrupt_type harp_irq_type = {
+       "Harp-IRQ",
+       startup_harp_irq,
+       shutdown_harp_irq,
+       enable_harp_irq,
+       disable_harp_irq,
+       mask_and_ack_harp,
+       end_harp_irq
+};
+
+static void disable_harp_irq(unsigned int irq)
+{
+       unsigned val, flags;
+       unsigned maskReg;
+       unsigned mask;
+       int pri;
+
+       if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+               return;
+
+       pri = 15 - irq;
+
+       if (pri < 8) {
+               maskReg = EPLD_INTMASK0;
+       } else {
+               maskReg = EPLD_INTMASK1;
+               pri -= 8;
+       }
+
+       save_and_cli(flags);
+       mask = ctrl_inl(maskReg);
+       mask &= (~(1 << pri));
+#if defined(INVERT_INTMASK_WRITES)
+       mask ^= 0xff;
+#endif
+       ctrl_outl(mask, maskReg);
+       restore_flags(flags);
+}
+
+static void enable_harp_irq(unsigned int irq)
+{
+       unsigned flags;
+       unsigned maskReg;
+       unsigned mask;
+       int pri;
+
+       if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+               return;
+
+       pri = 15 - irq;
+
+       if (pri < 8) {
+               maskReg = EPLD_INTMASK0;
+       } else {
+               maskReg = EPLD_INTMASK1;
+               pri -= 8;
+       }
+
+       save_and_cli(flags);
+       mask = ctrl_inl(maskReg);
+
+
+       mask |= (1 << pri);
+
+#if defined(INVERT_INTMASK_WRITES)
+       mask ^= 0xff;
+#endif
+       ctrl_outl(mask, maskReg);
+
+       restore_flags(flags);
+}
+
+/* This functions sets the desired irq handler to be an overdrive type */
+static void __init make_harp_irq(unsigned int irq)
+{
+       disable_irq_nosync(irq);
+       irq_desc[irq].handler = &harp_irq_type;
+       disable_harp_irq(irq);
+}
+
+static void mask_and_ack_harp(unsigned int irq)
+{
+       disable_harp_irq(irq);
+}
+
+static void end_harp_irq(unsigned int irq)
+{
+       enable_harp_irq(irq);
+}
+
+void __init init_harp_irq(void)
+{
+       int i;
+
+#if !defined(INVERT_INTMASK_WRITES)
+       // On the harp these are set to enable an interrupt
+       ctrl_outl(0x00, EPLD_INTMASK0);
+       ctrl_outl(0x00, EPLD_INTMASK1);
+#else
+       // On the Overdrive the data is inverted before being stored in the reg
+       ctrl_outl(0xff, EPLD_INTMASK0);
+       ctrl_outl(0xff, EPLD_INTMASK1);
+#endif
+
+       for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+               make_harp_irq(i);
+       }
+}
diff --git a/arch/sh/stboards/led.c b/arch/sh/stboards/led.c
new file mode 100644 (file)
index 0000000..f7831e5
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * linux/arch/sh/stboards/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * This file contains ST40STB1 HARP and compatible code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include "harp.h"
+
+/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
+/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
+/* Works for HARP and overdrive */
+static void mach_led(int position, int value)
+{
+       if (value) {
+               ctrl_outl(EPLD_LED_ON, EPLD_LED);
+       } else {
+               ctrl_outl(EPLD_LED_OFF, EPLD_LED);
+       }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void heartbeat_harp(void)
+{
+       static unsigned cnt = 0, period = 0, dist = 0;
+
+       if (cnt == 0 || cnt == dist)
+               mach_led( -1, 1);
+       else if (cnt == 7 || cnt == dist+7)
+               mach_led( -1, 0);
+
+       if (++cnt > period) {
+               cnt = 0;
+               /* The hyperbolic function below modifies the heartbeat period
+                * length in dependency of the current (5min) load. It goes
+                * through the points f(0)=126, f(1)=86, f(5)=51,
+                * f(inf)->30. */
+               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+               dist = period / 4;
+       }
+}
+#endif
diff --git a/arch/sh/stboards/mach.c b/arch/sh/stboards/mach.c
new file mode 100644 (file)
index 0000000..614dd2a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * linux/arch/sh/stboards/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Machine vector for the STMicroelectronics STB1 HARP and compatible boards
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io_hd64465.h>
+#include <asm/hd64465.h>
+
+void setup_harp(void);
+void init_harp_irq(void);
+void heartbeat_harp(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_harp __initmv = {
+       mv_name:                "STB1 Harp",
+
+       mv_nr_irqs:             89 + HD64465_IRQ_NUM,
+
+       mv_inb:                 hd64465_inb,
+       mv_inw:                 hd64465_inw,
+       mv_inl:                 hd64465_inl,
+       mv_outb:                hd64465_outb,
+       mv_outw:                hd64465_outw,
+       mv_outl:                hd64465_outl,
+
+       mv_inb_p:               hd64465_inb_p,
+       mv_inw_p:               hd64465_inw,
+       mv_inl_p:               hd64465_inl,
+       mv_outb_p:              hd64465_outb_p,
+       mv_outw_p:              hd64465_outw,
+       mv_outl_p:              hd64465_outl,
+
+       mv_insb:                hd64465_insb,
+       mv_insw:                hd64465_insw,
+       mv_insl:                hd64465_insl,
+       mv_outsb:               hd64465_outsb,
+       mv_outsw:               hd64465_outsw,
+       mv_outsl:               hd64465_outsl,
+
+       mv_readb:               generic_readb,
+       mv_readw:               generic_readw,
+       mv_readl:               generic_readl,
+       mv_writeb:              generic_writeb,
+       mv_writew:              generic_writew,
+       mv_writel:              generic_writel,
+
+        mv_ioremap:             generic_ioremap,
+        mv_iounmap:             generic_iounmap,
+        mv_isa_port2addr:       hd64465_isa_port2addr,
+
+       mv_init_arch:           setup_harp,
+#ifdef CONFIG_PCI
+       mv_init_irq:            init_harp_irq,
+#endif
+#ifdef CONFIG_HEARTBEAT
+       mv_heartbeat:           heartbeat_harp,
+#endif
+        mv_rtc_gettimeofday:    sh_rtc_gettimeofday,
+        mv_rtc_settimeofday:    sh_rtc_settimeofday,
+};
+
+ALIAS_MV(harp)
diff --git a/arch/sh/stboards/pcidma.c b/arch/sh/stboards/pcidma.c
new file mode 100644 (file)
index 0000000..4753113
--- /dev/null
@@ -0,0 +1,42 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                          dma_addr_t * dma_handle)
+{
+       void *ret;
+       int gfp = GFP_ATOMIC;
+
+       ret = (void *) __get_free_pages(gfp, get_order(size));
+
+       if (ret != NULL) {
+               /* Is it neccessary to do the memset? */
+               memset(ret, 0, size);
+               *dma_handle = virt_to_bus(ret);
+       }
+       /* We must flush the cache before we pass it on to the device */
+       flush_cache_all();
+       return  P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+        unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+       free_pages(p1addr, get_order(size));
+}
diff --git a/arch/sh/stboards/setup.c b/arch/sh/stboards/setup.c
new file mode 100644 (file)
index 0000000..1d3a484
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * arch/sh/stboard/setup.c
+ *
+ * Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * STMicroelectronics ST40STB1 HARP and compatible support.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include "harp.h"
+/*
+ * Initialize the board
+ */
+int __init setup_harp(void)
+{
+#ifdef CONFIG_SH_STB1_HARP
+       unsigned long ic8_version, ic36_version;
+
+       ic8_version = ctrl_inl(EPLD_REVID2);
+       ic36_version = ctrl_inl(EPLD_REVID1);
+
+        printk("STMicroelectronics STB1 HARP initialisaton\n");
+        printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
+               (ic8_version >> 4) & 0xf, ic8_version & 0xf,
+               (ic36_version >> 4) & 0xf, ic36_version & 0xf);
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+       unsigned long version;
+
+       version = ctrl_inl(EPLD_REVID);
+
+        printk("STMicroelectronics STB1 Overdrive initialisaton\n");
+        printk("EPLD version: %d.%02d\n",
+              (version >> 4) & 0xf, version & 0xf);
+#else
+#error Undefined machine
+#endif
+        /* Currently all STB1 chips have problems with the sleep instruction,
+         * so disable it here.
+         */
+       disable_hlt();
+
+       return 0;
+}
index 82fda3484297165132849a24bfa93677b79627ac..e10d70bfdcc5df53eefb539a279562bb37a6b1f8 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.144 2001/06/01 08:12:10 davem Exp $
+# $Id: config.in,v 1.146 2001/06/16 04:15:26 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -36,6 +36,7 @@ define_bool CONFIG_HAVE_DEC_LOCK y
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_ISA n
+define_bool CONFIG_ISAPNP n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_PCMCIA n
@@ -235,71 +236,7 @@ if [ "$CONFIG_NET" = "y" ]; then
 
    bool 'Network device support' CONFIG_NETDEVICES
    if [ "$CONFIG_NETDEVICES" = "y" ]; then
-      tristate '  Dummy net driver support' CONFIG_DUMMY
-      tristate '  Bonding driver support' CONFIG_BONDING
-      tristate '  Universal TUN/TAP device driver support' CONFIG_TUN
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        if [ "$CONFIG_NETLINK" = "y" ]; then
-          tristate '  Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
-        fi
-      fi
-      tristate '  PPP (point-to-point) support' CONFIG_PPP
-      if [ ! "$CONFIG_PPP" = "n" ]; then
-         dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
-         dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
-         dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
-         dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
-         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-            dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
-         fi
-      fi
-      tristate '  SLIP (serial line) support' CONFIG_SLIP
-      if [ "$CONFIG_SLIP" != "n" ]; then
-        bool '    CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
-        bool '    Keepalive and linefill' CONFIG_SLIP_SMART
-        bool '    Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
-      fi
-
-      mainmenu_option next_comment
-      comment 'Ethernet (10 or 100Mbit)'
-
-      tristate 'Sun LANCE support' CONFIG_SUNLANCE
-      tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        tristate 'Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC
-      fi
-      tristate '  Sun QuadEthernet support' CONFIG_SUNQE
-      if [ "$CONFIG_PCI" = "y" ]; then
-        tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
-        tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
-        tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
-        tristate 'RealTek RTL-8139 support' CONFIG_8139TOO
-        tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
-        tristate 'VIA Rhine support' CONFIG_VIA_RHINE
-        tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100
-        tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
-      fi
-      endmenu
-
-      mainmenu_option next_comment
-      comment 'Ethernet (1000 Mbit)'
-
-      if [ "$CONFIG_PCI" = "y" ]; then
-         tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
-         if [ "$CONFIG_ACENIC" != "n" ]; then
-           bool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
-         fi
-         tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
-         tristate 'Sun GEM support' CONFIG_SUNGEM
-      fi
-      tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
-      endmenu
-
-      bool 'FDDI driver support' CONFIG_FDDI
-      if [ "$CONFIG_FDDI" = "y" ]; then
-          tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
-      fi
-
+      source drivers/net/Config.in
       if [ "$CONFIG_ATM" = "y" ]; then
        source drivers/atm/Config.in
       fi
@@ -330,6 +267,11 @@ mainmenu_option next_comment
 comment 'XFree86 DRI support'
 bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
 dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM
+dep_tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM
+dep_tristate '  ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM
+if [ "$CONFIG_DRM_R128" != "n" ]; then
+   define_bool CONFIG_AGP y
+fi
 endmenu
 
 source drivers/input/Config.in
index fbb4ed4c346cd508c4ad5625deefb90b7ddc5e30..a8ae55a1232bbcdea1c7161f754d2c883f1a6e1a 100644 (file)
@@ -26,6 +26,7 @@ CONFIG_HAVE_DEC_LOCK=y
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ISA is not set
+# CONFIG_ISAPNP is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
 # CONFIG_PCMCIA is not set
@@ -359,46 +360,119 @@ CONFIG_IEEE1394_RAWIO=m
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_APPLETALK is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
 CONFIG_TUN=m
-CONFIG_PPP=m
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-CONFIG_PPPOE=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
+CONFIG_NET_ETHERNET=y
 CONFIG_SUNLANCE=y
 CONFIG_HAPPYMEAL=y
 CONFIG_SUNBMAC=m
 CONFIG_SUNQE=m
-CONFIG_DE4X5=m
-CONFIG_TULIP=m
+CONFIG_SUNLANCE=y
+CONFIG_SUNGEM=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_ELMC is not set
+# CONFIG_ELMC_II is not set
 CONFIG_VORTEX=m
-CONFIG_8139TOO=m
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_DGRS=m
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=m
+# CONFIG_LNE390 is not set
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
 CONFIG_NE2K_PCI=m
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+CONFIG_EPIC100=m
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
-CONFIG_EEPRO100=m
-CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_WINBOND_840=m
+# CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
 CONFIG_ACENIC=m
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
-CONFIG_SK98LIN=m
-CONFIG_SUNGEM=y
 CONFIG_MYRI_SBUS=m
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_SK98LIN=m
 CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
 CONFIG_SKFP=m
+CONFIG_HIPPI=y
+# CONFIG_ROADRUNNER is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
 
 #
 # Unix 98 PTY support
@@ -417,6 +491,9 @@ CONFIG_VIDEO_DEV=y
 #
 CONFIG_DRM=y
 CONFIG_DRM_FFB=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_AGP=y
 
 #
 # Input core support
index 6220c2f11bd2fcfeb0f4a1d50a97cefda8d0c8fd..c0f418e29cfb870677dfc4e7021fd03f10403261 100644 (file)
@@ -390,7 +390,7 @@ kbd_wontreset:
                kbd_state, keyval);
 #endif
        mdelay(1);
-       inb(IOC_KARTRX);
+       ioc_readb(IOC_KARTRX);
        a5kkbd_sendbyte (HRST);
        kbd_state = KBD_INITRST;
        return 0;
@@ -407,13 +407,13 @@ kbd_error:
 static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
 {
        kbd_pt_regs = regs;
-       if (handle_rawcode(inb(IOC_KARTRX)))
+       if (handle_rawcode(ioc_readb(IOC_KARTRX)))
                tasklet_schedule(&keyboard_tasklet);
 }
 
 static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
 {
-       outb (kbd_txval[kbd_txtail], IOC_KARTTX);
+       ioc_writeb (kbd_txval[kbd_txtail], IOC_KARTTX);
        KBD_INCTXPTR(kbd_txtail);
        if (kbd_txtail == kbd_txhead)
                disable_irq(irq);
@@ -431,7 +431,7 @@ void __init a5kkbd_init_hw (void)
 
        if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
                panic("Could not allocate keyboard transmit IRQ!");
-       (void)inb(IOC_KARTRX);
+       (void)ioc_readb(IOC_KARTRX);
        if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
                panic("Could not allocate keyboard receive IRQ!");
 
index 27be184f91176e8ea6c11feeae02c93916ecb651..d6f609e545e8438847466562bb9e018a6718d424 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/random.h>
 #include <linux/ctype.h>
 #include <linux/kbd_ll.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 
 #include <asm/bitops.h>
@@ -37,6 +38,12 @@ extern struct tasklet_struct keyboard_tasklet;
 extern void kbd_reset_kdown(void);
 int kbd_read_mask;
 
+#define TX_DONE 0
+#define TX_SENT 1
+#define TX_SEND 2
+
+static volatile int tx_state;
+
 #define VERSION 100
 
 #define KBD_REPORT_ERR
@@ -233,8 +240,33 @@ static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
 
 static inline void ps2kbd_sendbyte(unsigned char val)
 {
-       while(!(inb(IOMD_KCTRL) & (1 << 7)));
-       outb(val, IOMD_KARTTX);
+       int tries = 3, timeout = 1000;
+
+       tx_state = TX_SEND;
+
+       do {
+               switch (tx_state) {
+               case TX_SEND:
+                       tx_state = TX_SENT;
+                       timeout = 1000;
+                       tries --;
+
+                       while(!(iomd_readb(IOMD_KCTRL) & (1 << 7)));
+                       iomd_writeb(val, IOMD_KARTTX);
+                       break;
+
+               case TX_SENT:
+                       udelay(1000);
+                       if (--timeout == 0) {
+                               printk(KERN_ERR "Keyboard timeout\n");
+                               tx_state = TX_DONE;
+                       }
+                       break;
+
+               case TX_DONE:
+                       break;
+               }
+       } while (tries > 0 && tx_state != TX_DONE);
 }
 
 static unsigned char status;
@@ -254,18 +286,30 @@ static void handle_rawcode(int keyval)
 
        if (keyval > 0x83) {
                switch (keyval) {
-                       case KBD_ESCAPEE0:
-                               ncodes = 2;
-                               bi = 0;
-                               break;
-                       case KBD_ESCAPEE1:
-                               ncodes = 3;
-                               bi = 0;
-                               break;
-                       case KBD_BREAK:
-                               status |= CODE_BREAK;
-                       default:
-                               return;
+               case KBD_ESCAPEE0:
+                       ncodes = 2;
+                       bi = 0;
+                       break;
+
+               case KBD_ESCAPEE1:
+                       ncodes = 3;
+                       bi = 0;
+                       break;
+
+               case KBD_ACK:
+                       tx_state = TX_DONE;
+                       return;
+
+               case KBD_RESEND:
+                       tx_state = TX_SEND;
+                       return;
+
+               case KBD_BREAK:
+                       status |= CODE_BREAK;
+                       return;
+
+               default:
+                       return;
                }
        }
 
@@ -278,6 +322,13 @@ static void handle_rawcode(int keyval)
                switch (buffer[0] << 8 | buffer[1]) {
                case ESCE0(0x11): keysym = K_RALT; break;
                case ESCE0(0x14): keysym = K_RCTL; break;
+               /*
+                * take care of MS extra keys (actually
+                * 0x7d - 0x7f, but last one is already K_NONE
+                */
+               case ESCE0(0x1f): keysym = 124;    break;
+               case ESCE0(0x27): keysym = 125;    break;
+               case ESCE0(0x2f): keysym = 126;    break;
                case ESCE0(0x4a): keysym = KP_SLH; break;
                case ESCE0(0x5a): keysym = KP_ENT; break;
                case ESCE0(0x69): keysym = K_END;  break;
@@ -320,8 +371,8 @@ static void ps2kbd_rx(int irq, void *dev_id, struct pt_regs *regs)
 {
        kbd_pt_regs = regs;
 
-       while (inb(IOMD_KCTRL) & (1 << 5))
-               handle_rawcode(inb(IOMD_KARTRX));
+       while (iomd_readb(IOMD_KCTRL) & (1 << 5))
+               handle_rawcode(iomd_readb(IOMD_KARTRX));
        tasklet_schedule(&keyboard_tasklet);
 }
 
@@ -332,10 +383,10 @@ static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs)
 int __init ps2kbd_init_hw(void)
 {
        /* Reset the keyboard state machine. */
-       outb(0, IOMD_KCTRL);
-       outb(8, IOMD_KCTRL);
+       iomd_writeb(0, IOMD_KCTRL);
+       iomd_writeb(8, IOMD_KCTRL);
+       iomd_readb(IOMD_KARTRX);
 
-       (void)IOMD_KARTRX;
        if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
                panic("Could not allocate keyboard receive IRQ!");
        if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0)
diff --git a/drivers/acorn/char/mouse_ps2.c b/drivers/acorn/char/mouse_ps2.c
new file mode 100644 (file)
index 0000000..27a1f5b
--- /dev/null
@@ -0,0 +1,289 @@
+/* 
+ * Driver for PS/2 mouse on IOMD interface
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/iomd.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*
+ *     PS/2 Auxiliary Device
+ */
+
+static struct aux_queue *queue;        /* Mouse data buffer. */
+static int aux_count = 0;
+/* used when we send commands to the mouse that expect an ACK. */
+static unsigned char mouse_reply_expected = 0;
+
+#define MAX_RETRIES    60              /* some aux operations take long time*/
+
+/*
+ *     Mouse Commands
+ */
+
+#define AUX_SET_RES            0xE8    /* Set resolution */
+#define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
+#define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
+#define AUX_GET_SCALE          0xE9    /* Get scaling factor */
+#define AUX_SET_STREAM         0xEA    /* Set stream mode */
+#define AUX_SET_SAMPLE         0xF3    /* Set sample rate */
+#define AUX_ENABLE_DEV         0xF4    /* Enable aux device */
+#define AUX_DISABLE_DEV                0xF5    /* Disable aux device */
+#define AUX_RESET              0xFF    /* Reset aux device */
+#define AUX_ACK                        0xFA    /* Command byte ACK. */
+
+#define AUX_BUF_SIZE           2048    /* This might be better divisible by
+                                          three to make overruns stay in sync
+                                          but then the read function would 
+                                          need a lock etc - ick */
+
+struct aux_queue {
+       unsigned long head;
+       unsigned long tail;
+       wait_queue_head_t proc_list;
+       struct fasync_struct *fasync;
+       unsigned char buf[AUX_BUF_SIZE];
+};
+
+/*
+ * Send a byte to the mouse.
+ */
+static void aux_write_dev(int val)
+{
+       while (!(iomd_readb(IOMD_MSECTL) & 0x80));
+       iomd_writeb(val, IOMD_MSEDAT);
+}
+
+/*
+ * Send a byte to the mouse & handle returned ack
+ */
+static void aux_write_ack(int val)
+{
+       while (!(iomd_readb(IOMD_MSECTL) & 0x80));
+       iomd_writeb(val, IOMD_MSEDAT);
+
+       /* we expect an ACK in response. */
+       mouse_reply_expected++;
+}
+
+static unsigned char get_from_queue(void)
+{
+       unsigned char result;
+
+       result = queue->buf[queue->tail];
+       queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+       return result;
+}
+
+static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int val = iomd_readb(IOMD_MSEDAT);
+
+       if (mouse_reply_expected) {
+               if (val == AUX_ACK) {
+                       mouse_reply_expected--;
+                       return;
+               }
+               mouse_reply_expected = 0;
+       }
+
+       add_mouse_randomness(val);
+       if (aux_count) {
+               int head = queue->head;
+
+               queue->buf[head] = val;
+               head = (head + 1) & (AUX_BUF_SIZE-1);
+               if (head != queue->tail) {
+                       queue->head = head;
+                       kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+                       wake_up_interruptible(&queue->proc_list);
+               }
+       }
+}
+
+static inline int queue_empty(void)
+{
+       return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+       int retval;
+
+       retval = fasync_helper(fd, filp, on, &queue->fasync);
+       if (retval < 0)
+               return retval;
+       return 0;
+}
+
+
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+       fasync_aux(-1, file, 0);
+       if (--aux_count)
+               return 0;
+       free_irq(IRQ_MOUSERX, AUX_DEV);
+       return 0;
+}
+
+/*
+ * Install interrupt handler.
+ * Enable auxiliary device.
+ */
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+       if (aux_count++)
+               return 0;
+
+       queue->head = queue->tail = 0;          /* Flush input queue */
+       if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse", 
+                       AUX_DEV)) {
+               aux_count--;
+               return -EBUSY;
+       }
+
+       aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
+
+       return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+                       size_t count, loff_t *ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       ssize_t i = count;
+       unsigned char c;
+
+       if (queue_empty()) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               add_wait_queue(&queue->proc_list, &wait);
+repeat:
+               current->state = TASK_INTERRUPTIBLE;
+               if (queue_empty() && !signal_pending(current)) {
+                       schedule();
+                       goto repeat;
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&queue->proc_list, &wait);
+       }
+       while (i > 0 && !queue_empty()) {
+               c = get_from_queue();
+               put_user(c, buffer++);
+               i--;
+       }
+       if (count-i) {
+               file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+               return count-i;
+       }
+       if (signal_pending(current))
+               return -ERESTARTSYS;
+       return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+                        size_t count, loff_t *ppos)
+{
+       ssize_t retval = 0;
+
+       if (count) {
+               ssize_t written = 0;
+
+               if (count > 32)
+                       count = 32; /* Limit to 32 bytes. */
+               do {
+                       char c;
+                       get_user(c, buffer++);
+                       aux_write_dev(c);
+                       written++;
+               } while (--count);
+               retval = -EIO;
+               if (written) {
+                       retval = written;
+                       file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+               }
+       }
+
+       return retval;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+       poll_wait(file, &queue->proc_list, wait);
+       if (!queue_empty())
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+struct file_operations psaux_fops = {
+       read:           read_aux,
+       write:          write_aux,
+       poll:           aux_poll,
+       open:           open_aux,
+       release:        release_aux,
+       fasync:         fasync_aux,
+};
+
+/*
+ * Initialize driver.
+ */
+static struct miscdevice psaux_mouse = {
+       PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+int __init psaux_init(void)
+{
+       /* Reset the mouse state machine. */
+       iomd_writeb(0, IOMD_MSECTL);
+       iomd_writeb(8, IOMD_MSECTL);
+  
+       misc_register(&psaux_mouse);
+       queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+       memset(queue, 0, sizeof(*queue));
+       queue->head = queue->tail = 0;
+       init_waitqueue_head(&queue->proc_list);
+
+       aux_write_ack(AUX_SET_SAMPLE);
+       aux_write_ack(100);                     /* 100 samples/sec */
+       aux_write_ack(AUX_SET_RES);
+       aux_write_ack(3);                       /* 8 counts per mm */
+       aux_write_ack(AUX_SET_SCALE21);         /* 2:1 scaling */
+
+       return 0;
+}
index 926daf7e0935f88c7d6944cd20d38282a03ca4ad..812a7821b6244dc23328afc4438bd3ec6936ee13 100644 (file)
@@ -34,9 +34,9 @@ mouse_rpc_irq(int irq, void *dev_id, struct pt_regs *regs)
        short x, y, dx, dy;
        int buttons;
 
-       x = (short)inl(IOMD_MOUSEX);
-       y = (short)inl(IOMD_MOUSEY);
-       buttons = (inl (0x800C4000) >> 4) & 7;
+       x = (short)iomd_readl(IOMD_MOUSEX);
+       y = (short)iomd_readl(IOMD_MOUSEY);
+       buttons = (__raw_readl(0xe0310000) >> 4) & 7;
 
        dx = x - old_x;
        old_x = x;
@@ -60,9 +60,9 @@ static int __init mouse_rpc_init(void)
        if (mousedev < 0)
                printk("rpcmouse: could not register mouse driver\n");
        else {
-               old_x = (short)inl(IOMD_MOUSEX);
-               old_y = (short)inl(IOMD_MOUSEY);
-               old_b = (inl (0x800C4000) >> 4) & 7;
+               old_x = (short)iomd_readl(IOMD_MOUSEX);
+               old_y = (short)iomd_readl(IOMD_MOUSEY);
+               old_b = (__raw_readl(0xe0310000) >> 4) & 7;
                if (request_irq(IRQ_VSYNCPULSE, mouse_rpc_irq, SA_SHIRQ, "mouse", &mousedev)) {
                        printk("rpcmouse: unable to allocate VSYNC interrupt\n");
                        unregister_busmouse(mousedev);
index 54329f72f98b728679754f34e216673f1e5db7d3..64dabc18db1c5f0b880ca6cc7b28e6b7a26a9ecb 100644 (file)
@@ -75,7 +75,7 @@ static void ether1_timeout(struct net_device *dev);
 
 /* ------------------------------------------------------------------------- */
 
-static const char version[] __initdata = KERN_INFO "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
 
 #define BUS_16 16
 #define BUS_8  8
@@ -990,7 +990,7 @@ static void __init ether1_banner(void)
        static unsigned int version_printed = 0;
 
        if (net_debug && version_printed++ == 0)
-               printk (version);
+               printk(KERN_INFO "%s", version);
 }
 
 static struct net_device * __init ether1_init_one(struct expansion_card *ec)
@@ -1045,7 +1045,6 @@ static struct net_device * __init ether1_init_one(struct expansion_card *ec)
 release:
        release_region(dev->base_addr, 16);
        release_region(dev->base_addr + 0x800, 4096);
-free:
        unregister_netdev(dev);
        kfree(dev);
 out:
index 5d4795596b2fd4cc5bfdbae62034024a09d17609..ede6094ee5351edb36275b552943735d66556006 100644 (file)
@@ -70,7 +70,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-static const char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
 
 #include "ether3.h"
 
@@ -777,7 +777,7 @@ static void __init ether3_banner(void)
        static unsigned version_printed = 0;
 
        if (net_debug && version_printed++ == 0)
-               printk(version);
+               printk(KERN_INFO "%s", version);
 }
 
 static const char * __init
index bdeac73656a6b73d46acec3a3c3acc464020d925..a5184513f7fd1e1f74b34d2e11e87f500267ea0d 100644 (file)
 #include <linux/ioport.h>
 #include <linux/blk.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/bitops.h>
 #include <asm/system.h>
 #include "acornscsi.h"
 #include "msgqueue.h"
 
+#include <scsi/scsicam.h>
+
 #define VER_MAJOR 2
 #define VER_MINOR 0
 #define VER_PATCH 6
@@ -206,24 +209,24 @@ static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
 static inline void
 sbic_arm_write(unsigned int io_port, int reg, int value)
 {
-    outb_t(reg, io_port);
-    outb_t(value, io_port + 4);
+    __raw_writeb(reg, io_port);
+    __raw_writeb(value, io_port + 4);
 }
 
 #define sbic_arm_writenext(io,val) \
-       outb_t((val), (io) + 4)
+       __raw_writeb((val), (io) + 4)
 
 static inline
 int sbic_arm_read(unsigned int io_port, int reg)
 {
     if(reg == ASR)
-          return inl_t(io_port) & 255;
-    outb_t(reg, io_port);
-    return inl_t(io_port + 4) & 255;
+          return __raw_readl(io_port) & 255;
+    __raw_writeb(reg, io_port);
+    return __raw_readl(io_port + 4) & 255;
 }
 
 #define sbic_arm_readnext(io) \
-       inb_t((io) + 4)
+       __raw_readb((io) + 4)
 
 #ifdef USE_DMAC
 #define dmac_read(io_port,reg) \
@@ -2858,7 +2861,7 @@ static struct expansion_card *ecs[MAX_ECARDS];
  * Params   : host - host to setup
  */
 static
-void acornscsi_init(AS_Host *host)
+void acornscsi_host_init(AS_Host *host)
 {
     memset(&host->stats, 0, sizeof (host->stats));
     queue_initialise(&host->queues.issue);
@@ -2926,7 +2929,7 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
            host->scsi.irq = NO_IRQ;
        }
 
-       acornscsi_init(host);
+       acornscsi_host_init(host);
 
        ++count;
     }
@@ -3118,9 +3121,40 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
     return pos;
 }
 
-#ifdef MODULE
+static Scsi_Host_Template acornscsi_template = {
+       module:                 THIS_MODULE,
+       proc_info:              acornscsi_proc_info,
+       name:                   "AcornSCSI",
+       detect:                 acornscsi_detect,
+       release:                acornscsi_release,
+       info:                   acornscsi_info,
+       queuecommand:           acornscsi_queuecmd,
+       abort:                  acornscsi_abort,
+       reset:                  acornscsi_reset,
+       bios_param:             scsicam_bios_param,
+       can_queue:              16,
+       this_id:                7,
+       sg_tablesize:           SG_ALL,
+       cmd_per_lun:            2,
+       unchecked_isa_dma:      0,
+       use_clustering:         DISABLE_CLUSTERING
+};
 
-Scsi_Host_Template driver_template = ACORNSCSI_3;
+static int __init acornscsi_init(void)
+{
+       acornscsi_template.module = THIS_MODULE;
+       scsi_register_module(MODULE_SCSI_HA, &acornscsi_template);
+       if (acornscsi_template.present)
+               return 0;
 
-#include "../../scsi/scsi_module.c"
-#endif
+       scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+       return -ENODEV;
+}
+
+static void __exit acornscsi_exit(void)
+{
+       scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+}
+
+module_init(acornscsi_init);
+module_exit(acornscsi_exit);
index a674b05db6edfb41479fdeac2339126699cc3682..74a92d525c0a8ee9c8db8fc2913df6a40168aadd 100644 (file)
 #ifndef ACORNSCSI_H
 #define ACORNSCSI_H
 
-#ifndef ASM
-extern int acornscsi_detect (Scsi_Host_Template *);
-extern int acornscsi_release (struct Scsi_Host *);
-extern const char *acornscsi_info (struct Scsi_Host *);
-extern int acornscsi_queuecmd (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int acornscsi_abort (Scsi_Cmnd *);
-extern int acornscsi_reset (Scsi_Cmnd *, unsigned int);
-extern int acornscsi_proc_info (char *, char **, off_t, int, int, int);
-extern int acornscsi_biosparam (Disk *, kdev_t, int []);
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
-#include "linux/proc_fs.h"
-
-#include <scsi/scsicam.h>
-
-#define ACORNSCSI_3 {                                                  \
-proc_info:             acornscsi_proc_info,                            \
-name:                  "AcornSCSI",                                    \
-detect:                        acornscsi_detect,                               \
-release:               acornscsi_release,      /* Release */           \
-info:                  acornscsi_info,                                 \
-queuecommand:          acornscsi_queuecmd,                             \
-abort:                 acornscsi_abort,                                \
-reset:                 acornscsi_reset,                                \
-bios_param:            scsicam_bios_param,                             \
-can_queue:             CAN_QUEUE,              /* can_queue */         \
-this_id:               7,                      /* this id */           \
-sg_tablesize:          SG_ALL,                 /* sg_tablesize */      \
-cmd_per_lun:           CMD_PER_LUN,            /* cmd_per_lun */       \
-unchecked_isa_dma:     0,                      /* unchecked isa dma */ \
-use_clustering:                DISABLE_CLUSTERING                              \
-       }
-
-#ifndef HOSTS_C
-
 /* SBIC registers */
 #define OWNID                  0
 #define OWNID_FS1              (1<<7)
@@ -405,7 +359,4 @@ typedef struct acornscsi_hostdata {
     struct status_entry status[9][STATUS_BUFFER_SIZE];
 } AS_Host;
 
-#endif /* ndef HOSTS_C */
-
-#endif /* ndef ASM */
 #endif /* ACORNSCSI_H */
index e9aad1da069056a806d466914b20d368a736fca5..e9b41d153375e338d310f07631e245a7ed345300 100644 (file)
@@ -293,19 +293,19 @@ acpi_os_mem_in32 (ACPI_PHYSICAL_ADDRESS phys_addr)
 void
 acpi_os_mem_out8 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT8 value)
 {
-       *(u8*) (u32) phys_addr = value;
+       *(u8*) phys_to_virt(phys_addr) = value;
 }
 
 void
 acpi_os_mem_out16 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT16 value)
 {
-       *(u16*) (u32) phys_addr = value;
+       *(u16*) phys_to_virt(phys_addr) = value;
 }
 
 void
 acpi_os_mem_out32 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT32 value)
 {
-       *(u32*) (u32) phys_addr = value;
+       *(u32*) phys_to_virt(phys_addr) = value;
 }
 
 ACPI_STATUS
index 3de74d517115fa8a1a0ae3301af80bf9b01f65fd..926646d2b5f57bc43e1f30c1d3c86f77db1109cb 100644 (file)
@@ -613,19 +613,21 @@ static int command_do (amb_dev * dev, command * cmd) {
     while (timeout) {
       // go to sleep
       // PRINTD (DBG_CMD, "wait: sleeping %lu for command", timeout);
+      set_current_state(TASK_UNINTERRUPTIBLE);
       timeout = schedule_timeout (timeout);
-      // woken up by timeout or signal
     }
     
     // wait for my slot to be reached (all waiters are here or above, until...)
     while (ptrs->out != my_slot) {
       PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out);
+      set_current_state(TASK_UNINTERRUPTIBLE);
       schedule();
     }
     
     // wait on my slot (... one gets to its slot, and... )
     while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) {
       PRINTD (DBG_CMD, "wait: command slot completion");
+      set_current_state(TASK_UNINTERRUPTIBLE);
       schedule();
     }
     
@@ -1986,6 +1988,7 @@ static int __init do_loader_command (volatile loader_block * lb,
   
   while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS))
     if (timeout) {
+      set_current_state(TASK_UNINTERRUPTIBLE);
       timeout = schedule_timeout (timeout);
     } else {
       PRINTD (DBG_LOAD|DBG_ERR, "command %d timed out", cmd);
@@ -2110,12 +2113,15 @@ static int amb_reset (amb_dev * dev, int diags) {
     unsigned long timeout;
     // 4.2 second wait
     timeout = HZ*42/10;
-    while (timeout)
+    while (timeout) {
+      set_current_state(TASK_UNINTERRUPTIBLE);
       timeout = schedule_timeout (timeout);
+    }
     // half second time-out
     timeout = HZ/2;
     while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready)))
       if (timeout) {
+        set_current_state(TASK_UNINTERRUPTIBLE);
        timeout = schedule_timeout (timeout);
       } else {
        PRINTD (DBG_LOAD|DBG_ERR, "reset timed out");
@@ -2255,8 +2261,10 @@ static void __init amb_ucode_version (amb_dev * dev) {
   u32 minor;
   command cmd;
   cmd.request = cpu_to_be32 (SRB_GET_VERSION);
-  while (command_do (dev, &cmd))
+  while (command_do (dev, &cmd)) {
+    set_current_state(TASK_UNINTERRUPTIBLE);
     schedule();
+  }
   major = be32_to_cpu (cmd.args.version.major);
   minor = be32_to_cpu (cmd.args.version.minor);
   PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor);
@@ -2280,8 +2288,10 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) {
   }
   
   cmd.request = cpu_to_be32 (SRB_GET_BIA);
-  while (command_do (dev, &cmd))
+  while (command_do (dev, &cmd)) {
+    set_current_state(TASK_UNINTERRUPTIBLE);
     schedule();
+  }
   lower4 = be32_to_cpu (cmd.args.bia.lower4);
   upper2 = be32_to_cpu (cmd.args.bia.upper2);
   PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2);
@@ -2362,7 +2372,7 @@ static int __init amb_probe (void) {
   struct pci_dev * pci_dev;
   int devs;
   
-  void do_pci_device (void) {
+  void __init do_pci_device (void) {
     amb_dev * dev;
     
     // read resources from PCI configuration space
index e0931afd60a166d1d9e9018ec67d916ed45f0b74..999fd91044585337da5e88bcb53d1e105d5bae12 100644 (file)
@@ -2024,8 +2024,10 @@ fore200e_get_esi(struct fore200e* fore200e)
     if (!prom)
        return -ENOMEM;
     ok = fore200e->bus->prom_read(fore200e, prom);
-    if (ok < 0)
+    if (ok < 0) {
+       fore200e_kfree(prom);
        return -EBUSY;
+    }
        
     printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", 
           fore200e->name, 
index 320dd0ac8a4278fd4d8e32d097b6a81337911bae..6bcb190411215ca49729c1a35a0657f39fa25597 100644 (file)
@@ -144,18 +144,18 @@ static void idt77105_restart_timer_func(unsigned long dummy)
 static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero)
 {
        unsigned long flags;
-       int error;
+       struct idt77105_stats stats;
 
-       error = 0;
        save_flags(flags);
        cli();
-       if (arg)
-               error = copy_to_user(arg,&PRIV(dev)->stats,
-                   sizeof(struct idt77105_stats));
-       if (zero && !error)
-               memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
+       memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats));
+       if (zero)
+               memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats));
        restore_flags(flags);
-       return error ? -EFAULT : sizeof(struct idt77105_stats);
+       if (arg == NULL)
+               return 0;
+       return copy_to_user(arg, &PRIV(dev)->stats,
+                   sizeof(struct idt77105_stats)) ? -EFAULT : 0;
 }
 
 
index a5345ad85324aeedbaac46e9ba94353f57017759..54f791167c5ce31da077156d982ab9e240c0af63 100644 (file)
@@ -97,6 +97,10 @@ MODULE_PARM(IA_RX_BUF_SZ, "i");
 MODULE_PARM(IADebugFlag, "i");
 #endif
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver only works on 32-bit platforms
+#endif
+
 /**************************** IA_LIB **********************************/
 
 static void ia_init_rtn_q (IARTN_Q *que) 
index abe762f8644b58160153988ff91530d34f730c04..a7a9e9c18fd1c157eca43f72c11a2abd347e8e87 100644 (file)
@@ -62,6 +62,9 @@
 #include "idt77105.h"
 #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver requires a 32-bit platform
+#endif
 
 /* Additional code ************************************************************/
 
index 8f06133342943c8b7adcdb57128c42f0782f76a7..7d278f9df2fca6980213e5aa0d9678acca0b8e04 100644 (file)
@@ -86,16 +86,17 @@ static int set_framing(struct atm_dev *dev,unsigned char framing)
 static int get_sense(struct atm_dev *dev,u8 *arg)
 {
        unsigned long flags;
-       int error;
+       unsigned char s[3];
 
        save_flags(flags);
        cli();
-       error = put_user(GET(C11R),arg) || put_user(GET(C12R),arg+1) ||
-           put_user(GET(C13R),arg+2);
+       s[0] = GET(C11R);
+       s[1] = GET(C12R);
+       s[2] = GET(C13R);
        restore_flags(flags);
-       error = error || put_user(0xff,arg+3) || put_user(0xff,arg+4) ||
-           put_user(0xff,arg+5);
-       return error ? -EFAULT : 0;
+       return (put_user(s[0], arg) || put_user(s[1], arg+1) ||
+           put_user(s[2], arg+2) || put_user(0xff, arg+3) ||
+           put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0;
 }
 
 
index 86df59d8eba400e58c8b64b4fe4684fdbe1e8ddd..470e63299e2bb88362451dc8a54aa9dd7ea4e20f 100644 (file)
@@ -255,9 +255,7 @@ static void refill_pool(struct atm_dev *dev,int pool)
 
 static void drain_free(struct atm_dev *dev,int pool)
 {
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) kfree_skb(skb);
+       skb_queue_purge(&ZATM_DEV(dev)->pool[pool]);
 }
 
 
@@ -1464,6 +1462,9 @@ static int __init zatm_start(struct atm_dev *dev)
 
        DPRINTK("zatm_start\n");
        zatm_dev = ZATM_DEV(dev);
+       zatm_dev->rx_map = zatm_dev->tx_map = NULL;
+       for (i = 0; i < NR_MBX; i++)
+               zatm_dev->mbx_start[i] = 0;
        if (request_irq(zatm_dev->irq,&zatm_int,SA_SHIRQ,DEV_LABEL,dev)) {
                printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
                    dev->number,zatm_dev->irq);
@@ -1496,25 +1497,27 @@ static int __init zatm_start(struct atm_dev *dev)
            "%ld VCs\n",dev->number,NR_SHAPERS,pools,rx,
            (zatm_dev->mem-curr*4)/VC_SIZE);
        /* create mailboxes */
-       for (i = 0; i < NR_MBX; i++) zatm_dev->mbx_start[i] = 0;
        for (i = 0; i < NR_MBX; i++)
                if (mbx_entries[i]) {
                        unsigned long here;
 
                        here = (unsigned long) kmalloc(2*MBX_SIZE(i),
                            GFP_KERNEL);
-                       if (!here) return -ENOMEM;
+                       if (!here) {
+                               error = -ENOMEM;
+                               goto out;
+                       }
                        if ((here^(here+MBX_SIZE(i))) & ~0xffffUL)/* paranoia */
                                here = (here & ~0xffffUL)+0x10000;
+                       zatm_dev->mbx_start[i] = here;
                        if ((here^virt_to_bus((void *) here)) & 0xffff) {
                                printk(KERN_ERR DEV_LABEL "(itf %d): system "
                                    "bus incompatible with driver\n",
                                    dev->number);
-                               kfree((void *) here);
-                               return -ENODEV;
+                               error = -ENODEV;
+                               goto out;
                        }
                        DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i));
-                       zatm_dev->mbx_start[i] = here;
                        zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff;
                        zout(virt_to_bus((void *) here) >> 16,MSH(i));
                        zout(virt_to_bus((void *) here),MSL(i));
@@ -1523,15 +1526,25 @@ static int __init zatm_start(struct atm_dev *dev)
                        zout(here & 0xffff,MWA(i));
                }
        error = start_tx(dev);
-       if (error) return error;
+       if (error) goto out;
        error = start_rx(dev);
-       if (error) return error;
+       if (error) goto out;
        error = dev->phy->start(dev);
-       if (error) return error;
+       if (error) goto out;
        zout(0xffffffff,IMR); /* enable interrupts */
        /* enable TX & RX */
        zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR);
        return 0;
+    out:
+       for (i = 0; i < NR_MBX; i++)
+               if (zatm_dev->mbx_start[i] != 0)
+                       kfree((void *) zatm_dev->mbx_start[i]);
+       if (zatm_dev->rx_map != NULL)
+               kfree(zatm_dev->rx_map);
+       if (zatm_dev->tx_map != NULL)
+               kfree(zatm_dev->tx_map);
+       free_irq(zatm_dev->irq, dev);
+       return error;
 }
 
 
@@ -1681,22 +1694,16 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
                case ZATM_GETTHIST:
                        {
                                int i;
-
+                               struct zatm_t_hist hs[ZATM_TIMER_HISTORY_SIZE];
                                save_flags(flags);
                                cli();
-                               for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) {
-                                       if (!copy_to_user(
-                                           (struct zatm_t_hist *) arg+i,
-                                           &zatm_dev->timer_history[
+                               for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++)
+                                       hs[i] = zatm_dev->timer_history[
                                            (zatm_dev->th_curr+i) &
-                                           (ZATM_TIMER_HISTORY_SIZE-1)],
-                                           sizeof(struct zatm_t_hist)))
-                                                continue;
-                                       restore_flags(flags);
-                                       return -EFAULT;
-                               }
+                                           (ZATM_TIMER_HISTORY_SIZE-1)];
                                restore_flags(flags);
-                               return 0;
+                               return copy_to_user((struct zatm_t_hist *) arg,
+                                   hs, sizeof(hs)) ? -EFAULT : 0;
                        }
 #endif
                default:
@@ -1828,11 +1835,11 @@ int __init zatm_detect(void)
                            zatm_dev),GFP_KERNEL);
                        if (!zatm_dev) {
                                printk(KERN_EMERG "zatm.c: memory shortage\n");
-                               goto out;
+                               return devs;
                        }
                }
        }
-out:
+       kfree(zatm_dev);
        return devs;
 }
 
index 923db9506664798d9d79e471384103a800a35886..391abec031b99b62a6fa7eade1546a85ac6d74e1 100644 (file)
@@ -610,7 +610,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                {
                        /* Copy the data into the buffer we created */ 
                        if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
+                       {
+                               kfree(buff);
                                return -EFAULT;
+                       }
                }
                if ((c = cmd_alloc(h , 0)) == NULL)
                {
@@ -680,6 +683,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                        {
                                kfree(buff);
                                cmd_free(h, c, 0);
+                               return -EFAULT;
                        }
                 }
                 kfree(buff);
index 870c6bc183253b40f8dfc73540f487cbd904f3b6..cf8c4c066b6e6eb0ada3b679246c5a062ac32c8f 100644 (file)
@@ -753,6 +753,10 @@ static int pt_ioctl(struct inode *inode,struct file *file,
                        pt_rewind(unit);
                        return 0;
 
+                   case MTWEOF:
+                       pt_write_fm(unit);
+                       return 0;
+
                    default:    
                        printk("%s: Unimplemented mt_op %d\n",PT.name,
                                        mtop.mt_op);
index 05be1eb2cd7b8e8681fd646ac2323ea6a97f4682..ce15a467cc3528112b8bc88293d82544014a555f 100644 (file)
@@ -420,6 +420,7 @@ static void __init ps2esdi_geninit(void)
        request_dma(dma_arb_level, "ed");
        request_region(io_base, 4, "ed");
        blksize_size[MAJOR_NR] = ps2esdi_blocksizes;
+       max_sectors[MAJOR_NR] = ps2esdi_maxsect;
 
        for (i = 0; i < ps2esdi_drives; i++) {
                register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
index f97c783cf3a2c09de385769c1642d88d2a281594..f4dee49d40f29c396d2c4e42839f1b1b7d4c0b3d 100644 (file)
@@ -33,6 +33,7 @@
 
 #define MAJOR_NR       FLOPPY_MAJOR
 #include <linux/blk.h>
+#include <linux/devfs_fs_kernel.h>
 
 static int floppy_blocksizes[2] = {512,512};
 static int floppy_sizes[2] = {2880,2880};
@@ -248,10 +249,7 @@ static int swim3_add_device(struct device_node *swims);
 int swim3_init(void);
 
 #ifndef CONFIG_PMAC_PBOOK
-static inline int check_media_bay(struct device_node *which_bay, int what)
-{
-       return 1;
-}
+#define check_media_bay(which, what)   1
 #endif
 
 static void swim3_select(struct floppy_state *fs, int sel)
@@ -1014,10 +1012,14 @@ static struct block_device_operations floppy_fops = {
        revalidate:             floppy_revalidate,
 };
 
+static devfs_handle_t floppy_devfs_handle;
+
 int swim3_init(void)
 {
        struct device_node *swim;
 
+       floppy_devfs_handle = devfs_mk_dir(NULL, "floppy", NULL);
+
        swim = find_devices("floppy");
        while (swim && (floppy_count < MAX_FLOPPIES))
        {
@@ -1034,7 +1036,7 @@ int swim3_init(void)
 
        if (floppy_count > 0)
        {
-               if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+               if (devfs_register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
                        printk(KERN_ERR "Unable to get major %d for floppy\n",
                               MAJOR_NR);
                        return -EBUSY;
@@ -1051,7 +1053,9 @@ static int swim3_add_device(struct device_node *swim)
 {
        struct device_node *mediabay;
        struct floppy_state *fs = &floppy_states[floppy_count];
-       
+       char floppy_name[16];
+       devfs_handle_t floppy_handle;
+
        if (swim->n_addrs < 2)
        {
                printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
@@ -1108,6 +1112,12 @@ static int swim3_add_device(struct device_node *swim)
 
        printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
                mediabay ? "in media bay" : "");
+       sprintf(floppy_name, "%s%d", floppy_devfs_handle ? "" : "floppy",
+                       floppy_count);
+       floppy_handle = devfs_register(floppy_devfs_handle, floppy_name, 
+                       DEVFS_FL_DEFAULT, MAJOR_NR, floppy_count, 
+                       S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, 
+                       &floppy_fops, NULL);
 
        floppy_count++;
        
index ad36f0135b7d479dfe3b327cec957b81806c8cc1..feb6ce8c243fbb6c3419814c1873d9884bd6bbc6 100644 (file)
@@ -80,6 +80,10 @@ static const char *mcdx_c_version
 #define        mcdx_drive_map mcdx
 #include "mcdx.h"
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver only works on 32-bit platforms
+#endif
+
 #ifndef HZ
 #error HZ not defined
 #endif
index 6703254ada6c5aa75c42dd3de2b198ef673c14bf..c8c0c73e1ac832a0f41fb60c206d507729b9e5e9 100644 (file)
@@ -875,6 +875,9 @@ static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg)
        } else {
                agp_segment *segment;
 
+               if (reserve.seg_count >= 16384)
+                       return -EINVAL;
+                       
                segment = kmalloc((sizeof(agp_segment) * reserve.seg_count),
                                  GFP_KERNEL);
 
index 83d609c20a8d742f00c0b107796f447231e3c6ea..ba42e8e2853cf8249deb06fde312428d8678c6e3 100644 (file)
@@ -743,7 +743,7 @@ static unsigned char *cy_isa_addresses[] = {
 #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
 #ifdef MODULE
-static int maddr[NR_CARDS] = { 0, };
+static long maddr[NR_CARDS] = { 0, };
 static int irq[NR_CARDS]  = { 0, };
 
 MODULE_PARM(maddr, "1-" __MODULE_STRING(NR_CARDS) "l");
@@ -2983,10 +2983,11 @@ cy_write(struct tty_struct * tty, int from_user,
         return 0;
     }
 
-    CY_LOCK(info, flags);
     if (from_user) {
        down(&tmp_buf_sem);
        while (1) {
+           int c1;
+           
            c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                SERIAL_XMIT_SIZE - info->xmit_head));
            if (c <= 0)
@@ -2999,23 +3000,30 @@ cy_write(struct tty_struct * tty, int from_user,
                }
                break;
            }
-           c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+           CY_LOCK(info, flags);
+           c1 = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                        SERIAL_XMIT_SIZE - info->xmit_head));
+                       
+           if (c1 < c)
+               c = c1;
            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
            info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
            info->xmit_cnt += c;
+            CY_UNLOCK(info, flags);
            buf += c;
            count -= c;
            ret += c;
        }
        up(&tmp_buf_sem);
     } else {
+       CY_LOCK(info, flags);
        while (1) {
            c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, 
                        SERIAL_XMIT_SIZE - info->xmit_head));
-           if (c <= 0) {
+               
+           if (c <= 0)
                break;
-           }
+
            memcpy(info->xmit_buf + info->xmit_head, buf, c);
            info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
            info->xmit_cnt += c;
@@ -3023,8 +3031,8 @@ cy_write(struct tty_struct * tty, int from_user,
            count -= c;
            ret += c;
        }
+        CY_UNLOCK(info, flags);
     }
-    CY_UNLOCK(info, flags);
 
     info->idle_stats.xmit_bytes += ret;
     info->idle_stats.xmit_idle   = jiffies;
index 933fd0cd26330d09ae80fc80bb5a8fa14c1d788b..aa260730acba1aae77622c0a4cdcc8453101b468 100644 (file)
@@ -91,10 +91,13 @@ static int drm_alloc_queue(drm_device_t *dev)
                atomic_dec(&dev->queuelist[i]->use_count);
        }
                                /* Allocate a new queue */
-       down(&dev->struct_sem);
        
        queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+       if(queue == NULL)
+               return -ENOMEM; 
+
        memset(queue, 0, sizeof(*queue));
+       down(&dev->struct_sem);
        atomic_set(&queue->use_count, 1);
        
        ++dev->queue_count;
index 56dd2441efe8c4ed059f29bc42bb117b757e3285..f6c532d8acfa0a4b7d963421298a7d44f3e9fed0 100644 (file)
@@ -38,7 +38,10 @@ void drm_dma_setup(drm_device_t *dev)
 {
        int i;
        
-       dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+       if (!(dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER))) {
+                printk(KERN_ERR "drm_dma_setup: can't drm_alloc dev->dma");
+                return;
+        }       
        memset(dev->dma, 0, sizeof(*dev->dma));
        for (i = 0; i <= DRM_MAX_ORDER; i++)
                memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
index 427194b8790024c77cff9c713090f0802f0ba959..f949b3f519bf8b7cc66f135712a7861f45ae28ed 100644 (file)
@@ -1286,6 +1286,8 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,
        DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
                  vertex.idx, vertex.used, vertex.discard);
 
+       if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
        i810_dma_dispatch_vertex( dev, 
                                  dma->buflist[ vertex.idx ], 
                                  vertex.discard, vertex.used );
@@ -1409,7 +1411,7 @@ int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
        if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
                return -EFAULT;
 
-       if(d.idx > dma->buf_count) return -EINVAL;
+       if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
        buf = dma->buflist[ d.idx ];
        buf_priv = buf->dev_private;
        if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
index 6ac3d6059c6edecfb18f7aeb151e0912d343cc84..15fa3cd70d889206028c1b0d291be717d5cea986 100644 (file)
@@ -832,6 +832,7 @@ int mga_iload(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
+       if(iload.idx < 0 || iload.idx > dma->buf_count) return -EINVAL;
        buf = dma->buflist[iload.idx];
        buf_priv = buf->dev_private;
        bus_address = buf->bus_address;
@@ -874,6 +875,8 @@ int mga_vertex(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
+       if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
        buf = dma->buflist[vertex.idx];
        buf_priv = buf->dev_private;
 
@@ -920,6 +923,7 @@ int mga_indices(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
+       if(indices.idx < 0 || indices.idx > dma->buf_count) return -EINVAL;
        buf = dma->buflist[indices.idx];
        buf_priv = buf->dev_private;
 
index ca062a09bd0d016a0dadb3872efdda2b78c2ff86..ea2d376363807570cf18a09b2a189aabe2c63284 100644 (file)
@@ -92,6 +92,7 @@ int drm_proc_init(drm_device_t *dev)
                if (!drm_dev_root) {
                        DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
                        remove_proc_entry("dri", NULL);
+                       break;
                }
                if (drm_dev_root->nlink == 2) break;
                drm_dev_root = NULL;
index 320bd4c3021a7620752ad53965c844dbfcd6309d..bdab93544ab86f241823cd37a7845f1af27974dc 100644 (file)
@@ -132,6 +132,11 @@ int radeon_addbufs_agp(struct inode *inode, struct file *filp,
                buf->dev_priv_size = sizeof(drm_radeon_buf_priv_t);
                buf->dev_private   = drm_alloc(sizeof(drm_radeon_buf_priv_t),
                                               DRM_MEM_BUFS);
+                if (!buf->dev_private) {
+                        up(&dev->struct_sem);
+                        atomic_dec(&dev->buf_alloc);
+                        return -ENOMEM;
+                }
                memset(buf->dev_private, 0, buf->dev_priv_size);
 
 #if DRM_DMA_HISTOGRAM
index 6c44bbe0d3f511db9971ecabf8bbf4db85d0f63f..2a4433adda4a2be7df0ea9d16b5f311bd8f370ec 100644 (file)
 #include "epca.h"
 #include "epcaconfig.h"
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver only works on 32-bit platforms
+#endif
+
 /* ---------------------- Begin defines ------------------------ */
 
 #define VERSION            "1.3.0.1-LK"
index 4798fd75eb5d282c0e0e4adceed00ce493cfe23d..04789ae98db944759fe983b24cf6d54ca38eecb8 100644 (file)
@@ -957,7 +957,7 @@ static int startup(struct esp_struct * info)
                if (!dma_buffer)
                        info->stat_flags |= ESP_STAT_USE_PIO;
                else if (request_dma(dma, "esp serial")) {
-                       free_pages((unsigned int)dma_buffer,
+                       free_pages((unsigned long)dma_buffer,
                                   get_order(DMA_BUFFER_SZ));
                        dma_buffer = 0;
                        info->stat_flags |= ESP_STAT_USE_PIO;
@@ -1061,7 +1061,7 @@ static void shutdown(struct esp_struct * info)
 
                if (!current_port) {
                        free_dma(dma);
-                       free_pages((unsigned int)dma_buffer,
+                       free_pages((unsigned long)dma_buffer,
                                   get_order(DMA_BUFFER_SZ));
                        dma_buffer = 0;
                }               
@@ -2770,7 +2770,7 @@ void cleanup_module(void)
        }
 
        if (dma_buffer)
-               free_pages((unsigned int)dma_buffer,
+               free_pages((unsigned long)dma_buffer,
                        get_order(DMA_BUFFER_SZ));
 
        if (tmp_buf)
index 6c935491c460efc2a5722ecd56e3ff13a6bb5f77..b7e3d1953d256aaef7eea2f2a9ad95d42cb40b96 100644 (file)
@@ -232,19 +232,40 @@ static int i810tco_ioctl (struct inode *inode, struct file *file,
        }
 }
 
+/*
+ * 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 i810tco_pci_tbl[] __initdata = {
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0,   PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,   PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,   PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,  PCI_ANY_ID, PCI_ANY_ID, },
+       { 0, },
+};
+MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
+
 static struct pci_dev *i810tco_pci;
 
 static unsigned char i810tco_getdevice (void)
 {
+       struct pci_dev *dev;
        u8 val1, val2;
        u16 badr;
        /*
-        *      Find the PCI device which has vendor id 0x8086
-        *      and device ID 0x2410
+        *      Find the PCI device
         */
-       i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL,
-                                      PCI_DEVICE_ID_INTEL_82801AA_0, NULL);
-       if (i810tco_pci) {
+
+       pci_for_each_dev(dev) {
+               if (pci_match_device(i810tco_pci_tbl, dev))
+                       break;
+       }
+
+       if ((i810tco_pci = dev)) {
                /*
                 *      Find the ACPI base I/O address which is the base
                 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
index 459dec3759d574612baa275632ec669f8dde1596..5c34fd07f5cfa7a1b8a5ca6555710e9c3a53137e 100644 (file)
@@ -132,10 +132,10 @@ static void remove_client_block(struct r3964_info *pInfo,
 
 static int  r3964_open(struct tty_struct *tty);
 static void r3964_close(struct tty_struct *tty);
-static int  r3964_read(struct tty_struct *tty, struct file *file,
-                     unsigned char *buf, unsigned int nr);
-static int  r3964_write(struct tty_struct * tty, struct file * file,
-                      const unsigned char * buf, unsigned int nr);
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+                     unsigned char *buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+                      const unsigned char * buf, size_t nr);
 static int r3964_ioctl(struct tty_struct * tty, struct file * file,
                        unsigned int cmd, unsigned long arg);
 static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
@@ -1238,8 +1238,8 @@ static void r3964_close(struct tty_struct *tty)
     MOD_DEC_USE_COUNT;
 }
 
-static int r3964_read(struct tty_struct *tty, struct file *file,
-                     unsigned char *buf, unsigned int nr)
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+                         unsigned char *buf, size_t nr)
 {
    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
    struct r3964_client_info *pClient;
@@ -1299,8 +1299,8 @@ repeat:
    return -EPERM;
 }
 
-static int r3964_write(struct tty_struct * tty, struct file * file,
-                      const unsigned char *data, unsigned int count)
+static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+                          const unsigned char *data, size_t count)
 {
    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
    struct r3964_block_header *pHeader;
index 1086559df069afe1f2d4b2d270e77929e260c6d0..05a69587eead3a820f0245fbac9617c77fb0e786 100644 (file)
@@ -113,7 +113,7 @@ static int nvram_open_mode;         /* special open modes */
 #define        NVRAM_EXCL              2               /* opened with O_EXCL */
 
 #define        RTC_FIRST_BYTE          14      /* RTC register number of first NVRAM byte */
-#define        NVRAM_BYTES                     50      /* number of NVRAM bytes */
+#define        NVRAM_BYTES                     128     /* number of NVRAM bytes */
 
 
 static int mach_check_checksum( void );
index 34aa6cfbdd5a406beb5903b24a9c798eb5ec2939..b228cd6281f77befcf916d57c204b95764a05dbc 100644 (file)
@@ -4,6 +4,14 @@
  *
  * 20/08/2000  RMK     use __ioremap to map flash into virtual memory
  *                     make a few more places use "volatile"
+ * 22/05/2001  RMK     - Lock read against write
+ *                     - merge printk level changes (with mods) from Alan Cox.
+ *                     - use *ppos as the file position, not file->f_pos.
+ *                     - fix check for out of range pos and r/w size
+ *
+ * Please note that we are tampering with the only flash chip in the
+ * machine, which contains the bootup code.  We therefore have the
+ * power to convert these machines into doorstops...
  */
 
 #include <linux/module.h>
@@ -16,6 +24,7 @@
 #include <linux/sched.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 #include <linux/init.h>
 
 #include <asm/hardware/dec21285.h>
 /*****************************************************************************/
 #include <asm/nwflash.h>
 
-//#define MINIKERNEL 1          //export flash write, erase routines for MiniKernel
-
-#ifndef MINIKERNEL
-#define MSTATIC static
-#else
-#define MSTATIC
-#endif
-
-#define        NWFLASH_VERSION "6.3"
+#define        NWFLASH_VERSION "6.4"
 
-MSTATIC void kick_open(void);
-MSTATIC int get_flash_id(void);
-MSTATIC int erase_block(int nBlock);
-MSTATIC int write_block(unsigned long p, const char *buf, int count);
-static int open_flash(struct inode *inodep, struct file *filep);
+static void kick_open(void);
+static int get_flash_id(void);
+static int erase_block(int nBlock);
+static int write_block(unsigned long p, const char *buf, int count);
 static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg);
 static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos);
 static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
@@ -58,27 +58,10 @@ static int flashdebug;              //if set - we will display progress msgs
 static int gbWriteEnable;
 static int gbWriteBase64Enable;
 static volatile unsigned char *FLASH_BASE;
-MSTATIC int gbFlashSize = KFLASH_SIZE;
+static int gbFlashSize = KFLASH_SIZE;
 
 extern spinlock_t gpio_lock;
 
-static struct file_operations flash_fops =
-{
-       owner:          THIS_MODULE,
-       llseek:         flash_llseek,
-       read:           flash_read,
-       write:          flash_write,
-       ioctl:          flash_ioctl,
-       open:           open_flash,
-};
-
-static struct miscdevice flash_miscdev =
-{
-       FLASH_MINOR,
-       "nwflash",
-       &flash_fops
-};
-
 /*
  * the delay routine - it is often required to let the flash "breeze"...
  */
@@ -88,7 +71,7 @@ void flash_wait(int timeout)
        schedule_timeout(timeout);
 }
 
-MSTATIC int get_flash_id(void)
+static int get_flash_id(void)
 {
        volatile unsigned int c1, c2;
 
@@ -123,23 +106,8 @@ MSTATIC int get_flash_id(void)
        return c2;
 }
 
-static int open_flash(struct inode *inodep, struct file *filep)
-{
-       int id;
-
-       id = get_flash_id();
-       if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
-               printk("Flash: incorrect ID 0x%04X.\n", id);
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
 static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
 {
-//      printk("Flash_ioctl: cmd = 0x%X.\n",cmd);
-
        switch (cmd) {
        case CMD_WRITE_DISABLE:
                gbWriteBase64Enable = 0;
@@ -159,41 +127,48 @@ static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cm
                gbWriteEnable = 0;
                return -EINVAL;
        }
-
        return 0;
 }
 
-
-
-static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+static ssize_t flash_read(struct file *file, char *buf, size_t size, loff_t * ppos)
 {
-       unsigned long p = file->f_pos;
-       int read;
+       struct inode *inode = file->f_dentry->d_inode;
+       unsigned long p = *ppos;
+       unsigned int count = size;
+       int ret = 0;
 
        if (flashdebug)
-               printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n",
-                      (unsigned int) p, (unsigned int) buf, count);
+               printk(KERN_DEBUG "flash_read: flash_read: offset=0x%lX, buffer=%p, count=0x%X.\n",
+                      p, buf, count);
 
+       if (count)
+               ret = -ENXIO;
 
-       if (count < 0)
-               return -EINVAL;
+       if (p < gbFlashSize) {
+               if (count > gbFlashSize - p)
+                       count = gbFlashSize - p;
 
-       if (count > gbFlashSize - p)
-               count = gbFlashSize - p;
-
-       read = 0;
+               /*
+                * We now lock against reads and writes. --rmk
+                */
+               if (down_interruptible(&inode->i_sem))
+                       return -ERESTARTSYS;
 
-       if (copy_to_user(buf, (void *)(FLASH_BASE + p), count))
-               return -EFAULT;
-       read += count;
-       file->f_pos += read;
-       return read;
+               ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
+               if (ret == 0) {
+                       ret = count;
+                       *ppos += count;
+               }
+               up(&inode->i_sem);
+       }
+       return ret;
 }
 
-static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+static ssize_t flash_write(struct file *file, const char *buf, size_t size, loff_t * ppos)
 {
        struct inode *inode = file->f_dentry->d_inode;
-       unsigned long p = file->f_pos;
+       unsigned long p = *ppos;
+       unsigned int count = size;
        int written;
        int nBlock, temp, rc;
        int i, j;
@@ -209,20 +184,19 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
                return -EINVAL;
 
        /*
-        * if byte count is -ve or to big - error!
+        * check for out of range pos or count
         */
-       if (count < 0 || count > gbFlashSize - p)
-               return -EINVAL;
+       if (p >= gbFlashSize)
+               return count ? -ENXIO : 0;
 
+       if (count > gbFlashSize - p)
+               count = gbFlashSize - p;
+                       
        if (verify_area(VERIFY_READ, buf, count))
                return -EFAULT;
 
-
        /*
-        * We now should lock around writes.  Really, we shouldn't
-        * allow the flash to be opened more than once in write
-        * mode though (note that you can't stop two processes having
-        * it open even then). --rmk
+        * We now lock against reads and writes. --rmk
         */
        if (down_interruptible(&inode->i_sem))
                return -ERESTARTSYS;
@@ -246,11 +220,12 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
                temp -= 1;
 
        if (flashdebug)
-               printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock);
+               printk(KERN_DEBUG "flash_write: writing %d block(s) "
+                       "starting at %d.\n", temp, nBlock);
 
        for (; temp; temp--, nBlock++) {
                if (flashdebug)
-                       printk("FlashWrite: erasing block %d.\n", nBlock);
+                       printk(KERN_DEBUG "flash_write: erasing block %d.\n", nBlock);
 
                /*
                 * first we have to erase the block(s), where we will write...
@@ -264,14 +239,12 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
                } while (rc && i < 10);
 
                if (rc) {
-                       if (flashdebug)
-                               printk("FlashWrite: erase error %X. Aborting...\n", rc);
-
+                       printk(KERN_ERR "flash_write: erase error %x\n", rc);
                        break;
                }
                if (flashdebug)
-                       printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n",
-                              (unsigned int) p, (unsigned int) buf, count - written);
+                       printk(KERN_DEBUG "flash_write: writing offset %lX, from buf "
+                               "%p, bytes left %X.\n", p, buf, count - written);
 
                /*
                 * write_block will limit write to space left in this block
@@ -296,17 +269,16 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
 
                }
                if (rc < 0) {
-                       if (flashdebug)
-                               printk("FlashWrite: write error %X. Aborting...\n", rc);
+                       printk(KERN_ERR "flash_write: write error %X\n", rc);
                        break;
                }
                p += rc;
                buf += rc;
                written += rc;
-               file->f_pos += rc;
+               *ppos += rc;
 
                if (flashdebug)
-                       printk("FlashWrite: written 0x%X bytes OK.\n", written);
+                       printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written);
        }
 
        /*
@@ -331,8 +303,8 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
 static long long flash_llseek(struct file *file, long long offset, int orig)
 {
        if (flashdebug)
-               printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n",
-                      (unsigned int) offset, (unsigned int) orig);
+               printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n",
+                      (unsigned int) offset, orig);
 
        switch (orig) {
        case 0:
@@ -362,7 +334,7 @@ static long long flash_llseek(struct file *file, long long offset, int orig)
  * so just go ahead and erase, what requested!
  */
 
-MSTATIC int erase_block(int nBlock)
+static int erase_block(int nBlock)
 {
        volatile unsigned int c1;
        volatile unsigned char *pWritePtr;
@@ -440,13 +412,12 @@ MSTATIC int erase_block(int nBlock)
         * check if erase errors were reported
         */
        if (c1 & 0x20) {
-               if (flashdebug)
-                       printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr);
+               printk(KERN_ERR "flash_erase: err at %p\n", pWritePtr);
+
                /*
                 * reset error
                 */
                *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
-
                return -2;
        }
 
@@ -459,9 +430,8 @@ MSTATIC int erase_block(int nBlock)
 
        for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) {
                if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) {
-                       if (flashdebug)
-                               printk("Flash_erase: verify err at %X = %X.\n",
-                                      (unsigned int) pWritePtr, temp1);
+                       printk(KERN_ERR "flash_erase: verify err at %p = %X\n",
+                              pWritePtr, temp1);
                        return -1;
                }
        }
@@ -473,7 +443,7 @@ MSTATIC int erase_block(int nBlock)
 /*
  * write_block will limit number of bytes written to the space in this block
  */
-MSTATIC int write_block(unsigned long p, const char *buf, int count)
+static int write_block(unsigned long p, const char *buf, int count)
 {
        volatile unsigned int c1;
        volatile unsigned int c2;
@@ -591,7 +561,7 @@ MSTATIC int write_block(unsigned long p, const char *buf, int count)
                         */
                        if (time_before(jiffies, timeout)) {
                                if (flashdebug)
-                                       printk("FlashWrite: Retrying write (addr=0x%X)...\n",
+                                       printk(KERN_DEBUG "write_block: Retrying write at 0x%X)n",
                                               pWritePtr - FLASH_BASE);
 
                                /*
@@ -609,7 +579,7 @@ MSTATIC int write_block(unsigned long p, const char *buf, int count)
 
                                goto WriteRetry;
                        } else {
-                               printk("Timeout in flash write! (addr=0x%X) Aborting...\n",
+                               printk(KERN_ERR "write_block: timeout at 0x%X\n",
                                       pWritePtr - FLASH_BASE);
                                /*
                                 * return error -2
@@ -636,9 +606,8 @@ MSTATIC int write_block(unsigned long p, const char *buf, int count)
                        return -EFAULT;
                buf++;
                if ((c1 = *pWritePtr++) != c) {
-                       if (flashdebug)
-                               printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n",
-                                      (unsigned int) pWritePtr, c1, c);
+                       printk(KERN_ERR "write_block: verify error at 0x%X (%02X!=%02X)\n",
+                              pWritePtr - FLASH_BASE, c1, c);
                        return 0;
                }
        }
@@ -647,7 +616,7 @@ MSTATIC int write_block(unsigned long p, const char *buf, int count)
 }
 
 
-MSTATIC void kick_open(void)
+static void kick_open(void)
 {
        unsigned long flags;
 
@@ -665,7 +634,23 @@ MSTATIC void kick_open(void)
        udelay(25);
 }
 
-MSTATIC int __init nwflash_init(void)
+static struct file_operations flash_fops =
+{
+       owner:          THIS_MODULE,
+       llseek:         flash_llseek,
+       read:           flash_read,
+       write:          flash_write,
+       ioctl:          flash_ioctl,
+};
+
+static struct miscdevice flash_miscdev =
+{
+       FLASH_MINOR,
+       "nwflash",
+       &flash_fops
+};
+
+static int __init nwflash_init(void)
 {
        int ret = -ENODEV;
 
@@ -677,6 +662,13 @@ MSTATIC int __init nwflash_init(void)
                        goto out;
 
                id = get_flash_id();
+               if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
+                       ret = -ENXIO;
+                       iounmap((void *)FLASH_BASE);
+                       printk("Flash: incorrect ID 0x%04X.\n", id);
+                       goto out;
+               }
+
                printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n",
                       NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024));
 
@@ -688,7 +680,7 @@ out:
        return ret;
 }
 
-MSTATIC void __exit nwflash_exit(void)
+static void __exit nwflash_exit(void)
 {
        misc_deregister(&flash_miscdev);
        iounmap((void *)FLASH_BASE);
index dac54515d6fcf291fc1967ba79a9cf1aaeca6657..9c9e00e7c30b6576833b3c88284c0b952d9cdafc 100644 (file)
@@ -194,7 +194,7 @@ int raw_ctl_ioctl(struct inode *inode,
                        break;
                
                minor = rq.raw_minor;
-               if (minor == 0 || minor > MINORMASK) {
+               if (minor <= 0 || minor > MINORMASK) {
                        err = -EINVAL;
                        break;
                }
index ff6e2d7c62ac91285385a99c045ac59b122b6445..e511a15e42514efed4a5a6f509102cb2d766f9e8 100644 (file)
@@ -174,9 +174,13 @@ static ssize_t fop_write(struct file * file, const char * buf, size_t count, lof
 
                /* now scan */
                for(ofs = 0; ofs != count; ofs++) 
+               {
+                       char c;
+                       if(get_user(c, buf+ofs))
+                               return -EFAULT;
                        if(buf[ofs] == 'V')
                                wdt_expect_close = 1;
-
+               }
                /* Well, anyhow someone wrote to us, we should return that favour */
                next_heartbeat = jiffies + WDT_HEARTBEAT;
                return 1;
index 7d75d03fa584228a30e98ed108f6690d59006bad..6eeabcaed2c8895b5866c869f0b9b882ee57fcfc 100644 (file)
@@ -1035,7 +1035,11 @@ static int sci_init_drivers(void)
        memset(&sci_driver, 0, sizeof(sci_driver));
        sci_driver.magic = TTY_DRIVER_MAGIC;
        sci_driver.driver_name = "sci";
+#ifdef CONFIG_DEVFS_FS
+       sci_driver.name = "ttsc/%d";
+#else
        sci_driver.name = "ttySC";
+#endif
        sci_driver.major = SCI_MAJOR;
        sci_driver.minor_start = SCI_MINOR_START;
        sci_driver.num = SCI_NPORTS;
@@ -1070,7 +1074,11 @@ static int sci_init_drivers(void)
 #endif
 
        sci_callout_driver = sci_driver;
+#ifdef CONFIG_DEVFS_FS
+       sci_callout_driver.name = "cusc/%d";
+#else
        sci_callout_driver.name = "cusc";
+#endif
        sci_callout_driver.major = SCI_MAJOR+1;
        sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
        sci_callout_driver.read_proc = NULL;
index c290686c505bd6c77690101e937601395e114662..f24ed0c75ea2b9ed7266130b6e13edfb65905c38 100644 (file)
@@ -46,7 +46,7 @@
 # define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
 # define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
 # define SCI_AND_SCIF
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
 # define SCI_NPORTS 2
 # define SCI_INIT { \
   { {}, PORT_SCI,  0xffe00000, SCI_IRQS,      sci_init_pins_sci  }, \
@@ -294,7 +294,7 @@ static inline int sci_rxd_in(struct sci_port *port)
                return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
        return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
 static inline int sci_rxd_in(struct sci_port *port)
 {
 #ifndef SCIF_ONLY
index 742fe2f8ce9877952b0da9489ee9e38b19f91319..e528417d4c924350d9d205211efed93834253509 100644 (file)
@@ -467,7 +467,7 @@ static void my_hd (unsigned char *addr, int len)
        int i, j, ch;
 
        for (i=0;i<len;i+=16) {
-               printk ("%08x ", (int) addr+i);
+               printk ("%p ", addr+i);
                for (j=0;j<16;j++) {
                        printk ("%02x %s", addr[j+i], (j==7)?" ":"");
                }
@@ -1639,7 +1639,8 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
        int rc = 0;
        int *descr = (int *)arg, i;
        static struct sx_board *board = NULL;
-       int nbytes, offset, data;
+       int nbytes, offset;
+       unsigned long data;
        char *tmp;
 
        func_enter();
@@ -2098,7 +2099,7 @@ static int probe_sx (struct sx_board *board)
        func_enter();
 
        if (!IS_CF_BOARD (board)) {    
-               sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n", 
+               sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %lx.\n", 
                            board->base + SX_VPD_ROM);
 
                if (sx_debug & SX_DEBUG_PROBE)
@@ -2123,7 +2124,7 @@ static int probe_sx (struct sx_board *board)
        printheader ();
 
        if (!IS_CF_BOARD (board)) {
-               printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base);
+               printk (KERN_DEBUG "sx: Found an SX board at %lx\n", board->hw_base);
                printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ", 
                        vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
                printk (           "Manufactured: %d/%d\n", 
@@ -2140,7 +2141,7 @@ static int probe_sx (struct sx_board *board)
 
                if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
                        if (board->base & 0x8000) {
-                               printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base);
+                               printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->base);
                                printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
                        }
                }
@@ -2172,7 +2173,7 @@ static int probe_si (struct sx_board *board)
        int i;
 
        func_enter();
-       sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n", 
+       sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %lx.\n", 
                    board->base + SI2_ISA_ID_BASE);
 
        if (sx_debug & SX_DEBUG_PROBE)
@@ -2188,7 +2189,7 @@ static int probe_si (struct sx_board *board)
 
        printheader ();
 
-       printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base);
+       printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
        /* Compared to the SX boards, it is a complete guess as to what
                 this card is up to... */
 
@@ -2507,7 +2508,7 @@ static int __init sx_init(void)
 
                        board->irq = get_irq (pdev);
 
-                       sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d) %x.\n", 
+                       sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%lx(%d) %x.\n", 
                                    tint, boards[found].base, board->irq, board->flags);
 
                        if (probe_sx (board)) {
@@ -2569,8 +2570,8 @@ static int __init sx_init(void)
                        board->base2 =
                        board->base = (ulong) ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
 
-                       sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %x\n", board->hw_base);
-                       sx_dprintk(SX_DEBUG_PROBE, "base: %x\n", board->base);
+                       sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+                       sx_dprintk(SX_DEBUG_PROBE, "base: %lx\n", board->base);
                        board->irq = inb(board->eisa_base+0xc02)>>4; 
                        sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
                        
@@ -2602,7 +2603,7 @@ static void __exit sx_exit (void)
        for (i = 0; i < SX_NBOARDS; i++) {
                board = &boards[i];
                if (board->flags & SX_BOARD_INITIALIZED) {
-                       sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base);
+                       sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %lx\n", board->base);
                        /* The board should stop messing with us.
                           (actually I mean the interrupt) */
                        sx_reset (board);
index 8d77c3c773757591239a8046b3dc6a319e26418b..1979be5c5064b4cd2df02da0bfda20b47d488b7b 100644 (file)
@@ -36,9 +36,9 @@ struct sx_port {
 
 struct sx_board {
   int magic;
-  unsigned int base;
-  unsigned int base2;
-  unsigned int hw_base;
+  unsigned long base;
+  unsigned long base2;
+  unsigned long hw_base;
   int eisa_base;
   int port_base; /* Number of the first port */
   struct sx_port *ports;
index c8970b25b8b960d6489848bb32cc6fb4afec7864..fef02c4e61dbff2d20e4cf42847bf1aca27f55ea 100644 (file)
@@ -148,6 +148,7 @@ extern int serial167_init(void);
 extern long serial167_console_init(void);
 extern void console_8xx_init(void);
 extern int rs_8xx_init(void);
+extern void mac_scc_console_init(void);
 extern void hwc_console_init(void);
 extern void hwc_tty_init(void);
 extern void con3215_init(void);
@@ -2184,6 +2185,8 @@ void __init console_init(void)
 #ifdef CONFIG_SERIAL_CONSOLE
 #if (defined(CONFIG_8xx) || defined(CONFIG_8260))
        console_8xx_init();
+#elif defined(CONFIG_MAC_SERIAL)
+       mac_scc_console_init();
 #elif defined(CONFIG_SERIAL)
        serial_console_init();
 #endif /* CONFIG_8xx */
@@ -2307,9 +2310,6 @@ void __init tty_init(void)
 #ifdef CONFIG_COMPUTONE
        ip2_init();
 #endif
-#ifdef CONFIG_MAC_SERIAL
-       macserial_init();
-#endif
 #ifdef CONFIG_ROCKETPORT
        rp_init();
 #endif
index 367d5b9992911c35e91236c2a9daa1681dead3ba..1e07e0736a2a71dad3b2f1458ee0bc74f80d9735 100644 (file)
@@ -51,6 +51,16 @@ const char *quirk_drives[] = {
 };
 
 const char *bad_ata100_5[] = {
+       "IBM-DTLA-307075",
+       "IBM-DTLA-307060",
+       "IBM-DTLA-307045",
+       "IBM-DTLA-307030",
+       "IBM-DTLA-307020",
+       "IBM-DTLA-307015",
+       "IBM-DTLA-305040",
+       "IBM-DTLA-305030",
+       "IBM-DTLA-305020",
+       "WDC AC310200R",
        NULL
 };
 
index 73e4aafdbf8c1f4d8e9887b5ed31eb27ecbf5cee..4ee6682a1887309b277204b3f68d9b05a566196b 100644 (file)
@@ -283,13 +283,16 @@ extern void ide_init_slc90e66(ide_hwif_t *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
+extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
+extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
 extern void ide_init_sl82c105(ide_hwif_t *);
-extern void ide_dmacapable_sl82c105(ide_hwif_t *, unsigned long);
+#define PCI_W82C105    &pci_init_sl82c105
+#define DMA_W82C105    &dma_init_sl82c105
 #define INIT_W82C105   &ide_init_sl82c105
-#define DMA_W82C105    &ide_dmacapable_sl82c105
 #else
-#define INIT_W82C105   IDE_IGNORE
+#define PCI_W82C105    NULL
 #define DMA_W82C105    NULL
+#define INIT_W82C105   IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_TRM290
@@ -369,7 +372,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
        {DEVID_AEC6210, "AEC6210",      PCI_AEC62XX,    NULL,           INIT_AEC62XX,   DMA_AEC62XX,    {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
        {DEVID_AEC6260, "AEC6260",      PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    0 },
        {DEVID_AEC6260R,"AEC6260R",     PCI_AEC62XX,    ATA66_AEC62XX,  INIT_AEC62XX,   NULL,           {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},   OFF_BOARD,      0 },
-       {DEVID_W82C105, "W82C105",      NULL,           NULL,           INIT_W82C105,   DMA_W82C105,    {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
+       {DEVID_W82C105, "W82C105",      PCI_W82C105,    NULL,           INIT_W82C105,   DMA_W82C105,    {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
        {DEVID_UM8673F, "UM8673F",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
        {DEVID_UM8886A, "UM8886A",      NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
        {DEVID_UM8886BF,"UM8886BF",     NULL,           NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
index 4976e49dc2acf30efb5f2430d954ae354118f56d..bb6d84dcebf5e4b6fc674fbcff67236e890682f6 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <asm/ecard.h>
 
-static const card_ids __init rapide_cids[] = {
+static card_ids __init rapide_cids[] = {
        { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
        { 0xffff, 0xffff }
 };
index 2451e801d1e2c7e0df794ed908fc361b83fbf5ff..d868e5f4009f599936b7d3f64fca2565fb68dfde 100644 (file)
@@ -56,10 +56,9 @@ static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
 }
 
 /*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
+ * Configure the drive and chipset for PIO
  */
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
+static void config_for_pio(ide_drive_t *drive, int pio, int report)
 {
        ide_hwif_t *hwif = HWIF(drive);
        struct pci_dev *dev = hwif->pci_dev;
@@ -83,42 +82,212 @@ static void tune_sl82c105(ide_drive_t *drive, byte pio)
        if (ide_config_drive_speed(drive, xfer_mode) == 0)
                drv_ctrl = get_timing_sl82c105(&p);
 
+       if (drive->using_dma == 0) {
+               /*
+                * If we are actually using MW DMA, then we can not
+                * reprogram the interface drive control register.
+                */
+               pci_write_config_word(dev, reg, drv_ctrl);
+               pci_read_config_word(dev, reg, &drv_ctrl);
+
+               if (report) {
+                       printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+                              ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+               }
+       }
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       struct pci_dev *dev = hwif->pci_dev;
+       unsigned short drv_ctrl = 0x909;
+       unsigned int reg;
+
+       reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+       if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
+               drv_ctrl = 0x0240;
+
        pci_write_config_word(dev, reg, drv_ctrl);
-       pci_read_config_word(dev, reg, &drv_ctrl);
 
-       printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-              ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+       return 0;
 }
-#endif
 
-void __init ide_dmacapable_sl82c105(ide_hwif_t *hwif, unsigned long dmabase)
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+static int sl82c105_check_drive(ide_drive_t *drive)
 {
+       ide_dma_action_t dma_func = ide_dma_off_quietly;
+
+       do {
+               struct hd_driveid *id = drive->id;
+               ide_hwif_t *hwif = HWIF(drive);
+
+               if (!hwif->autodma)
+                       break;
+
+               if (!id || !(id->capability & 1))
+                       break;
+
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+                       dma_func = ide_dma_off;
+                       break;
+               }
+
+               if (id->field_valid & 2) {
+                       if  (id->dma_mword & 7 || id->dma_1word & 7)
+                               dma_func = ide_dma_on;
+                       break;
+               }
+
+               if (ide_dmaproc(ide_dma_good_drive, drive)) {
+                       dma_func = ide_dma_on;
+                       break;
+               }
+       } while (0);
+
+       return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * Our own dmaproc, only to intercept ide_dma_check
+ */
+static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+       switch (func) {
+       case ide_dma_check:
+               return sl82c105_check_drive(drive);
+       case ide_dma_on:
+               if (config_for_dma(drive))
+                       func = ide_dma_off;
+               /* fall through */
+       case ide_dma_off_quietly:
+       case ide_dma_off:
+               config_for_pio(drive, 4, 0);
+               break;
+       default:
+               break;
+       }
+       return ide_dmaproc(func, drive);
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, byte pio)
+{
+       config_for_pio(drive, pio, 1);
+
+       /*
+        * We support 32-bit I/O on this interface, and it
+        * doesn't have problems with interrupts.
+        */
+       drive->io_32bit = 1;
+       drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+       struct pci_dev *bridge;
        unsigned char rev;
 
-       pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &rev);
+       bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
+
+       /*
+        * If we are part of a Winbond 553
+        */
+       if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+               return -1;
+
+       if (bridge->bus != dev->bus ||
+           PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
+               return -1;
+
+       /*
+        * We need to find function 0's revision, not function 1
+        */
+       pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+       return rev;
+}
+
+/*
+ * Enable the PCI device
+ */
+unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+{
+       unsigned char ctrl_stat;
+
+       /*
+        * Enable the ports
+        */
+       pci_read_config_byte(dev, 0x40, &ctrl_stat);
+       pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
 
+       return dev->irq;
+}
+
+void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+       unsigned int rev;
+       byte dma_state;
+
+       dma_state = inb(dma_base + 2);
+       rev = sl82c105_bridge_revision(hwif->pci_dev);
        if (rev <= 5) {
                hwif->autodma = 0;
                hwif->drives[0].autotune = 1;
                hwif->drives[1].autotune = 1;
-               printk("    %s: revision %d, Bus-Master DMA disabled\n",
+               printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
                       hwif->name, rev);
+               dma_state &= ~0x60;
+       } else {
+               dma_state |= 0x60;
+               hwif->autodma = 1;
        }
-       ide_setup_dma(hwif, dmabase, 8);
+       outb(dma_state, dma_base + 2);
+
+       hwif->dmaproc = NULL;
+       ide_setup_dma(hwif, dma_base, 8);
+       if (hwif->dmaproc)
+               hwif->dmaproc = sl82c105_dmaproc;
 }
 
+/*
+ * Initialise the chip
+ */
 void __init ide_init_sl82c105(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       hwif->tuneproc = tune_sl82c105;
+}
 
-#ifdef CONFIG_ARCH_NETWINDER
-       unsigned char ctrl_stat;
+#else
 
-       pci_read_config_byte(dev, 0x40, &ctrl_stat);
-       pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+unsigned int pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+{
+       return ide_special_settings(dev, msg);
+}
 
-       hwif->tuneproc = tune_sl82c105;
-#else
+void dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+       ide_setup_dma(hwif, dma_base, 8);
+}
+
+void __init ide_init_sl82c105(ide_hwif_t *hwif)
+{
+       struct pci_dev *dev = hwif->pci_dev;
        unsigned short t16;
        unsigned int t32;
        pci_read_config_word(dev, PCI_COMMAND, &t16);
@@ -134,5 +303,6 @@ void __init ide_init_sl82c105(ide_hwif_t *hwif)
        printk("IDE control/status register: %08x\n",t32);
        pci_write_config_dword(dev, 0x40, 0x10ff08a1);
 #endif /* CONFIG_MBX */
-#endif
 }
+#endif
+
index 2bd93d450a31a97a91068ebd87417795bbea3673..7554c8465d816db1f86c88ee42f755fdf69aa899 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: c4.c,v 1.20.6.8 2001/05/17 21:15:33 kai Exp $
+ * $Id: c4.c,v 1.20.6.10 2001/06/09 15:14:15 kai Exp $
  * 
  * Module for AVM C4 & C2 card.
  * 
@@ -27,7 +27,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.9 $";
+static char *revision = "$Revision: 1.20.6.10 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
index e9d8bb2051400d46c0ff7a0da20f3c3be4622ce8..b8b2059f693cfc4c68489af03c14ffede1cc0fb8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: capi.c,v 1.44.6.11 2001/05/17 20:41:51 kai Exp $
+ * $Id: capi.c,v 1.44.6.12 2001/06/09 15:14:15 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
@@ -43,7 +43,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.44.6.11 $";
+static char *revision = "$Revision: 1.44.6.12 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
@@ -256,7 +256,6 @@ struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci)
 void capiminor_free(struct capiminor *mp)
 {
        struct capiminor **pp;
-       struct sk_buff *skb;
 
        pp = &minors;
        while (*pp) {
@@ -264,12 +263,9 @@ void capiminor_free(struct capiminor *mp)
                        *pp = (*pp)->next;
                        if (mp->ttyskb) kfree_skb(mp->ttyskb);
                        mp->ttyskb = 0;
-                       while ((skb = skb_dequeue(&mp->recvqueue)) != 0)
-                               kfree_skb(skb);
-                       while ((skb = skb_dequeue(&mp->inqueue)) != 0)
-                               kfree_skb(skb);
-                       while ((skb = skb_dequeue(&mp->outqueue)) != 0)
-                               kfree_skb(skb);
+                       skb_queue_purge(&mp->recvqueue);
+                       skb_queue_purge(&mp->inqueue);
+                       skb_queue_purge(&mp->outqueue);
                        capiminor_del_all_ack(mp);
                        kmem_cache_free(capiminor_cachep, mp);
                        MOD_DEC_USE_COUNT;
@@ -411,15 +407,12 @@ static struct capidev *capidev_alloc(struct file *file)
 static void capidev_free(struct capidev *cdev)
 {
        struct capidev **pp;
-       struct sk_buff *skb;
 
        if (cdev->applid)
                (*capifuncs->capi_release) (cdev->applid);
        cdev->applid = 0;
 
-       while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
-               kfree_skb(skb);
-       }
+       skb_queue_purge(&cdev->recvqueue);
        
        pp=&capidev_openlist;
        while (*pp && *pp != cdev) pp = &(*pp)->next;
index 704b7d347c564c274f930b6505daa6d1028ec124..bc41a5eab80363b3b85a7182b2b9e687cac6b80f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: kcapi.c,v 1.21.6.6 2001/05/17 20:41:51 kai Exp $
+ * $Id: kcapi.c,v 1.21.6.7 2001/06/09 15:14:15 kai Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
@@ -30,7 +30,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.21.6.6 $";
+static char *revision = "$Revision: 1.21.6.7 $";
 
 /* ------------------------------------------------------------- */
 
@@ -1129,14 +1129,12 @@ static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
 
 static __u16 capi_release(__u16 applid)
 {
-       struct sk_buff *skb;
        int i;
 
        if (!VALID_APPLID(applid) || APPL(applid)->releasing)
                return CAPI_ILLAPPNR;
        APPL(applid)->releasing++;
-       while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
-               kfree_skb(skb);
+       skb_queue_purge(&APPL(applid)->recv_queue);
        for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (cards[i].cardstate != CARD_RUNNING)
                        continue;
index 7587ccd0c14384bb7bc50e24f21d6d72d8d97a90..e8d3dc341839d418de067d2377fbbe815faeedf3 100644 (file)
@@ -857,7 +857,7 @@ int DivasGetList(dia_card_list_t *card_list)
 {
        int i;
 
-       bzero(card_list, sizeof(dia_card_list_t));
+       memset(card_list, 0, sizeof(dia_card_list_t));
 
        for(i = 0; i < DivasCardNext; i++)
        {
index a35979ac25b22d3464dd87b666f64ec06c4a53e0..2e598ab80aaf6b1d618dfd4450fe2c83b34e8ce1 100644 (file)
@@ -46,161 +46,110 @@ void UnlockDivas(void);
 int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, 
                         unsigned int command, unsigned long arg)
 {
-       dia_load_t *pDivaLoad;
-       dia_start_t *pDivaStart;
-       dia_config_t *pDivaConfig;
-       dia_log_t *pDivaLog;
        byte *pUserCards, card_i;
        word wCardNum;
-       mem_block_t *mem_block;
 
        switch (command)
        {
                case DIA_IOCTL_CONFIG:
-                       pDivaConfig = (dia_config_t *) arg;
-                       
-                       if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t)))
-                       {
-                               DivasCardConfig(pDivaConfig);
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n");
-                               return -1;
-                       }
-                               return 0;
+               {
+                       dia_config_t DivaConfig;
+                       if (copy_from_user(&DivaConfig, (void *)arg, sizeof(dia_config_t)))
+                               return -EFAULT;
+                       DivasCardConfig(&DivaConfig);
+                       return 0;
+               }
 
                case DIA_IOCTL_DETECT:
                        pUserCards = (byte *) arg;
 
                        if (!verify_area(VERIFY_WRITE, pUserCards, 20))
                        {
-                               put_user(DivasCardNext, pUserCards++);
+                               if(__put_user(DivasCardNext, pUserCards++))
+                                       return -EFAULT;
 
                                for (card_i=1; card_i < 20; card_i++)
                                {
-                                       put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++);
+                                       if(__put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++))
+                                               return -EFAULT;
                                }
                        }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n");
-                               return -1;
-                       }
+                       else return -EFAULT;
+
                        return 0;
 
                case DIA_IOCTL_START:
-                       pDivaStart = (dia_start_t *) arg;
-                       
-                       if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t)))
-                       {
-                               return DivasCardStart(pDivaStart->card_id);
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n");
-                               return -1;
-                       }
-
+               {
+                       dia_start_t DivaStart;
+                       if (copy_from_user(&DivaStart, (void *)arg, sizeof(dia_start_t)))
+                               return -EFAULT;
+                       return DivasCardStart(DivaStart.card_id);
+               }
 
                case DIA_IOCTL_FLAVOUR:
                        return 0;
 
                case DIA_IOCTL_LOAD:
-                       pDivaLoad = (dia_load_t *) arg;
-                       if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length))
+               {
+                       dia_load_t DivaLoad;
+                       if(copy_from_user(&DivaLoad, (void *)arg, sizeof(dia_load_t)))
+                               return -EFAULT;
+                       if (!verify_area(VERIFY_READ, DivaLoad.code,DivaLoad.length))
                        {
-                               if (DivasCardLoad(pDivaLoad))
+                               if (DivasCardLoad(&DivaLoad))
                                {
                                        printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n");
                                        return -EINVAL;
                                }
+                               return 0;
                        }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n");
-                               return -EINVAL;
-                       }
-                       return 0;
-
+                       return -EFAULT;
+               }
                case DIA_IOCTL_LOG:
-                       pDivaLog = (dia_log_t *) arg;
-                       
-                       if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t)))
-                       {
-                               DivasLog(pDivaLog);
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n");
-                               return -1;
-                       }
+               {
+                       dia_log_t DivaLog;
+                       if (copy_from_user(&DivaLog, (void *) arg, sizeof(dia_log_t)))
+                               return -EFAULT;
+                       DivasLog(&DivaLog);
                        return 0;
+               }
 
                case DIA_IOCTL_XLOG_REQ:
-                       
-                       if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word)))
-                       {
-                               wCardNum = * (word *) arg;
-                               DivasXlogReq(wCardNum);
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n");
-                               return -1;
-                       }
+                       if(get_user(wCardNum, (word *) arg))
+                               return -EFAULT;
+                       DivasXlogReq(wCardNum);
                        return 0;
 
                case DIA_IOCTL_GET_NUM:
-                       
-                       if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)))
-                       {
-                               * (int *) arg = DivasCardNext;
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n");
-                               return -1;
-                       }
+                       if(put_user(DivasCardNext, (int *)arg))
+                               return -EFAULT;
                        return 0;
 
                case DIA_IOCTL_GET_LIST:
+               {
+                       dia_card_list_t cards;
                        DPRINTF(("divas: DIA_IOCTL_GET_LIST"));
-                       
-                       if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t)))
-                       {
-                               DivasGetList((dia_card_list_t *)arg);
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n");
-                               return -1;
-                       }
+                       DivasGetList(&cards);
+                       if(copy_to_user((void *)arg, &cards, sizeof(cards)))
+                               return -EFAULT;
                        return 0;
-
+               }
                case DIA_IOCTL_GET_MEM:
-                       mem_block = (mem_block_t *) arg;
-                       
-                       if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t)))
-                       {
-                               DivasGetMem(mem_block);
-                       }
-                       else
-                       {
-                               printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n");
-                               return -1;
-                       }
+               {
+                       mem_block_t mem_block;
+                       if (copy_from_user(&mem_block, (void *)arg, sizeof(mem_block_t)))
+                               return -EFAULT;
+                       DivasGetMem(&mem_block);
                        return 0;
+               }
 
                case DIA_IOCTL_UNLOCK:
                        UnlockDivas();
                        return 0;
 
                default:
-                       printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command);
                        return -EINVAL;
        }
-       
        return -EINVAL;
 }
 
index d97a1f6fb3490cd716d124b017e0c91f249bd3db..3d6deaba2a8954f6400fae2eeb039a22a969ce74 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/proc_fs.h>
 #include <linux/sysctl.h>
 #include <linux/input.h>
+#include <linux/module.h>
 
 #ifdef CONFIG_MAC_ADBKEYCODES
 #include <linux/keyboard.h>
@@ -401,6 +402,8 @@ int mac_hid_keyboard_sends_linux_keycodes(void)
        return keyboard_sends_linux_keycodes;
 }
 
+EXPORT_SYMBOL(mac_hid_keyboard_sends_linux_keycodes);
+
 static int __init mac_hid_setup(char *str)
 {
        int ints[2];
@@ -448,6 +451,8 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
        return 0;
 }
 
+EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons);
+
 static void emumousebtn_input_register(void)
 {
        emumousebtn.name = "Macintosh mouse button emulation";
@@ -473,9 +478,19 @@ void __init mac_hid_init_hw(void)
 #ifdef CONFIG_MAC_ADBKEYCODES
        memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
 
-       if (!keyboard_sends_linux_keycodes)
+       if (!keyboard_sends_linux_keycodes) {
+#ifdef CONFIG_MAGIC_SYSRQ
+               ppc_md.ppc_kbd_sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
+               SYSRQ_KEY                = 0x69;
+#endif
                memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+       } else {
+#ifdef CONFIG_MAGIC_SYSRQ
+               ppc_md.ppc_kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+               SYSRQ_KEY                = 0x54;
 #endif
+       }
+#endif /* CONFIG_MAC_ADBKEYCODES */
 
 #ifdef CONFIG_MAC_EMUMOUSEBTN
        emumousebtn_input_register();
index 80616affaa4f67e70a1db32a733624d8fc0321c8..516adf79c2b91779a762db5fdf91416f695b5838 100644 (file)
@@ -305,7 +305,7 @@ int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
        return 1;
 }
 
-int mackbd_unexpected_up(unsigned char keycode)
+char mackbd_unexpected_up(unsigned char keycode)
 {
        return 0x80;
 }
index 1e01553488638e5370b10caf1f7269ca301149bf..f1bd198dfd6c05f4fe1039f68a67dcdb42b5e379 100644 (file)
@@ -448,7 +448,7 @@ static void transmit_chars(struct mac_serial *info)
                goto out;
        info->tx_active = 0;
 
-       if (info->x_char) {
+       if (info->x_char && !info->power_wait) {
                /* Send next char */
                write_zsdata(info->zs_channel, info->x_char);
                info->x_char = 0;
@@ -456,7 +456,8 @@ static void transmit_chars(struct mac_serial *info)
                goto out;
        }
 
-       if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+       if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
+           || info->power_wait) {
                write_zsreg(info->zs_channel, 0, RES_Tx_P);
                goto out;
        }
@@ -474,6 +475,14 @@ static void transmit_chars(struct mac_serial *info)
        restore_flags(flags);
 }
 
+static void powerup_done(unsigned long data)
+{
+       struct mac_serial *info = (struct mac_serial *) data;
+
+       info->power_wait = 0;
+       transmit_chars(info);
+}
+
 static _INLINE_ void status_handle(struct mac_serial *info)
 {
        unsigned char status;
@@ -730,7 +739,7 @@ static void do_softint(void *private_)
        }
 }
 
-static int startup(struct mac_serial * info, int can_sleep)
+static int startup(struct mac_serial * info)
 {
        int delay;
 
@@ -753,6 +762,18 @@ static int startup(struct mac_serial * info, int can_sleep)
 
        setup_scc(info);
 
+       if (delay) {
+               unsigned long flags;
+
+               /* delay is in ms */
+               save_flags(flags);
+               cli();
+               info->power_wait = 1;
+               mod_timer(&info->powerup_timer,
+                         jiffies + (delay * HZ + 999) / 1000);
+               restore_flags(flags);
+       }
+
        OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
 
        info->flags |= ZILOG_INITIALIZED;
@@ -761,15 +782,6 @@ static int startup(struct mac_serial * info, int can_sleep)
                enable_irq(info->rx_dma_irq);
        }
 
-       if (delay) {
-               if (can_sleep) {
-                       /* we need to wait a bit before using the port */
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(delay * HZ / 1000);
-               } else
-                       mdelay(delay);
-       }
-
        return 0;
 }
 
@@ -863,7 +875,7 @@ out:
                queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
-static void poll_rxdma(void *private_)
+static void poll_rxdma(unsigned long private_)
 {
        struct mac_serial       *info = (struct mac_serial *) private_;
        unsigned long flags;
@@ -2325,7 +2337,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
         * Start up serial port
         */
 
-       retval = startup(info, 1);
+       retval = startup(info);
        if (retval)
                return retval;
 
@@ -2426,6 +2438,10 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
                zss->rx_dma_irq = ch->intrs[2].line;
                spin_lock_init(&zss->rx_dma_lock);
        }
+
+       init_timer(&zss->powerup_timer);
+       zss->powerup_timer.function = powerup_done;
+       zss->powerup_timer.data = (unsigned long) zss;
 }
 
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
@@ -2680,14 +2696,7 @@ int macserial_init(void)
        return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-       macserial_init();
-       return 0;
-}
-
-void cleanup_module(void)
+void macserial_cleanup(void)
 {
        int i;
        unsigned long flags;
@@ -2717,7 +2726,9 @@ void cleanup_module(void)
                pmu_unregister_sleep_notifier(&serial_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 }
-#endif /* MODULE */
+
+module_init(macserial_init);
+module_exit(macserial_cleanup);
 
 #if 0
 /*
@@ -3119,7 +3130,7 @@ serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
                        struct mac_serial *info = &zs_soft[i];
                        if (info->flags & ZILOG_SLEEPING) {
                                info->flags &= ~ZILOG_SLEEPING;
-                               startup(info, 0);
+                               startup(info);
                        }
                }
                break;
index ff3f99345480285e0b7073b6590f6399a29c1200..376ce3209c5ac60e3f4c0e0e7c794958bea37077 100644 (file)
@@ -115,6 +115,7 @@ struct mac_serial {
        char is_irda;           /* is connected to an IrDA codec */
        unsigned char tx_active; /* character is being xmitted */
        unsigned char tx_stopped; /* output is suspended */
+       unsigned char power_wait; /* waiting for power-up delay to expire */
 
        /* We need to know the current clock divisor
         * to read the bps rate the chip has currently
@@ -186,6 +187,8 @@ struct mac_serial {
        void                    *dma_priv;
        struct timer_list       poll_dma_timer;
 #define RX_DMA_TIMER   (jiffies + 10*HZ/1000)
+
+       struct timer_list       powerup_timer;
 };
 
 
index 00b574f60b9c9d64e345fdac9b0ab7dd939a841a..b315d66ac84588ff54b94b726e94fa25c265ca90 100644 (file)
@@ -74,6 +74,10 @@ static void i2c_parport_attach(struct parport *port)
 {
   struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), 
                                      GFP_KERNEL);
+  if (!b) {
+         printk(KERN_ERR "i2c_parport: Memory allocation failed. Not attaching.\n");
+         return;
+  }
   b->i2c = parport_i2c_bus_template;
   b->i2c.data = parport_get_port (port);
   strncpy(b->i2c.name, port->name, 32);
index 10c8161209fc1404d68e7f2815e66238171727b2..6563cd44008cc575510c576ea406f4c045a8b37d 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
+#include <asm/semaphore.h>
 
 #include "planb.h"
 #include "saa7196.h"
@@ -326,41 +327,14 @@ static volatile struct dbdma_cmd *cmd_geo_setup(
 /* misc. supporting functions */
 /******************************/
 
-static void __planb_wait(struct planb *pb)
-{
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&pb->lockq, &wait);
-repeat:
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       if (pb->lock) {
-               schedule();
-               goto repeat;
-       }
-       remove_wait_queue(&pb->lockq, &wait);
-       current->state = TASK_RUNNING;
-}
-
-static inline void planb_wait(struct planb *pb)
-{
-       DEBUG("PlanB: planb_wait\n");
-       if(pb->lock)
-               __planb_wait(pb);
-}
-
 static inline void planb_lock(struct planb *pb)
 {
-       DEBUG("PlanB: planb_lock\n");
-       if(pb->lock)
-               __planb_wait(pb);
-       pb->lock = 1;
+       down(&pb->lock);
 }
 
 static inline void planb_unlock(struct planb *pb)
 {
-       DEBUG("PlanB: planb_unlock\n");
-       pb->lock = 0;
-       wake_up(&pb->lockq);
+       up(&pb->lock);
 }
 
 /***************/
@@ -2098,7 +2072,7 @@ static int init_planb(struct planb *pb)
        pb->tab_size = PLANB_MAXLINES + 40;
        pb->suspend = 0;
        pb->lock = 0;
-       init_waitqueue_head(&pb->lockq);
+       init_MUTEX(&pb->lock);
        pb->ch1_cmd = 0;
        pb->ch2_cmd = 0;
        pb->mask = 0;
index 98d5697c937476365e3339825778a390408db8ac..8a0faad16118a9a5bc138de88ebd12cfe53b5e3c 100644 (file)
@@ -174,8 +174,7 @@ struct planb {
        int     user;
        unsigned int tab_size;
        int     maxlines;
-       int lock;
-       wait_queue_head_t lockq;
+       struct semaphore lock;
        unsigned int    irq;                    /* interrupt number */
        volatile unsigned int intr_mask;
 
index 0477683a72a1833a0d5194f5a4778463a5ae6bd6..3d7f3bd16b508ddf2fd68aa53d32c887c9255e35 100644 (file)
@@ -373,6 +373,8 @@ static void videodev_proc_create_dev (struct video_device *vfd, char *name)
                return;
 
        p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
+       if (!p)
+               return;
        p->data = vfd;
        p->read_proc = videodev_proc_read;
 
index 5e9ae0d114fbf909d6666b270ab2ddade9e5299d..f8bde0f12d6bed2758f8c62fb260c1e2a417e128 100644 (file)
@@ -1025,7 +1025,7 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
                v.norm=VIDEO_MODE_PAL;
 #endif
                /* too many inputs? no decoder -> no channels */
-               if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
+               if (!ztv->have_decoder || v.channel < 0 ||  v.channel >= ztv->card->video_inputs)
                        return -EINVAL;
 
                /* now determine the name of the channel */
index 866625c981301d6e5828ce3bb6e02bc4783b60e9..389ac140fcf1907838cb6c2feefa336e759dac1d 100644 (file)
@@ -26,14 +26,15 @@ comment 'User Modules And Translation Layers'
    if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
       bool '    Write support for NFTL (BETA)' CONFIG_NFTL_RW
    fi
-fi
 
-source drivers/mtd/chips/Config.in
+   source drivers/mtd/chips/Config.in
+
+   source drivers/mtd/maps/Config.in
 
-source drivers/mtd/maps/Config.in
+   source drivers/mtd/devices/Config.in
 
-source drivers/mtd/devices/Config.in
+   source drivers/mtd/nand/Config.in
 
-source drivers/mtd/nand/Config.in
+fi
 
 endmenu
index 39d390a5d9980ef48c0c35a9f66573ff5c63421f..ece6677f0ae77657b9f4da781c411cdcb1c3111a 100644 (file)
@@ -191,6 +191,9 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
                ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098),
                (long) "3Com Etherlink III (TPC)" },
+       {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+               ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f7),
+               (long) "3Com Etherlink III compatible" },
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
                ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8),
                (long) "3Com Etherlink III compatible" },
@@ -1011,8 +1014,10 @@ MODULE_PARM_DESC(debug, "EtherLink III debug level (0-6)");
 MODULE_PARM_DESC(irq, "EtherLink III IRQ number(s) (assigned)");
 MODULE_PARM_DESC(xcvr,"EtherLink III tranceiver(s) (0=internal, 1=external)");
 MODULE_PARM_DESC(max_interrupt_work, "EtherLink III maximum events handled per interrupt");
+#ifdef CONFIG_ISAPNP
 MODULE_PARM(nopnp, "i");
 MODULE_PARM_DESC(nopnp, "EtherLink III disable ISA PnP support (0-1)");
+#endif /* CONFIG_ISAPNP */
 
 int
 init_module(void)
index 112d670401cedba5cd6144ad4d7d2beee959e484..0ac5827a2176ae8bccfa010a792c445eef26438e 100644 (file)
@@ -15,7 +15,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    fi
 fi
 
-tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000
+if [ "$CONFIG_ISAPNP" = "y" ]; then
+   tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 $CONFIG_ISAPNP
+fi
 
 #
 #      Ethernet
@@ -26,12 +28,9 @@ comment 'Ethernet (10 or 100Mbit)'
 
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-   if [ "$CONFIG_ARM" = "y" ]; then
-      if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
-        tristate '  AM79C961A support' CONFIG_ARM_AM79C961A
-      else
-        source drivers/acorn/net/Config.in
-      fi
+   dep_bool '  ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
+   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+      source drivers/acorn/net/Config.in
    fi
    if [ "$CONFIG_PPC" = "y" ]; then
       tristate '  MACE (Power Mac ethernet) support' CONFIG_MACE
@@ -64,6 +63,14 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
    if [ "$CONFIG_SUPERH" = "y" ]; then
       tristate '  National DP83902AV  support' CONFIG_STNIC
    fi
+   dep_tristate '  Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
+   if [ "$CONFIG_SBUS" = "y" -o "$CONFIG_PCI" = "y" ]; then
+      tristate '  Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+   fi
+   dep_tristate '  Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC $CONFIG_SBUS $CONFIG_EXPERIMENTAL
+   dep_tristate '  Sun QuadEthernet support' CONFIG_SUNQE $CONFIG_SBUS
+   dep_tristate '  Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
+   dep_tristate '  Sun GEM support' CONFIG_SUNGEM $CONFIG_PCI
    bool '  3COM cards' CONFIG_NET_VENDOR_3COM
    if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
       dep_tristate '    3c501 "EtherLink" support' CONFIG_EL1 $CONFIG_ISA
@@ -85,24 +92,28 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
    dep_tristate '  AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE $CONFIG_ISA
    bool '  Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
    if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
-      tristate '    WD80*3 support' CONFIG_WD80x3
-      if [ "$CONFIG_MCA" = "y" ]; then
-        tristate '    SMC Ultra MCA support' CONFIG_ULTRAMCA
+      dep_tristate '    WD80*3 support' CONFIG_WD80x3 $CONFIG_ISA
+      dep_tristate '    SMC Ultra MCA support' CONFIG_ULTRAMCA $CONFIG_MCA
+      if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ISAPNP" = "y" ]; then
+         tristate '    SMC Ultra support' CONFIG_ULTRA
       fi
-      tristate '    SMC Ultra support' CONFIG_ULTRA
       dep_tristate '    SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
-      tristate '    SMC 9194 support' CONFIG_SMC9194
+      dep_tristate '    SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA
    fi
    bool '  Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
    if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
-      dep_tristate '    NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_EXPERIMENTAL
-      tristate '    NI5210 support' CONFIG_NI52
-      tristate '    NI6510 support' CONFIG_NI65
+      dep_tristate '    NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_ISA $CONFIG_EXPERIMENTAL
+      dep_tristate '    NI5210 support' CONFIG_NI52 $CONFIG_ISA
+      dep_tristate '    NI6510 support' CONFIG_NI65 $CONFIG_ISA
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+      if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+         tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+      fi
+   fi
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+      tristate '  DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
    fi
-   tristate '  DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
       tristate '  HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
    fi
@@ -131,7 +142,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       tristate '  NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
       tristate '  IBM LAN Adapter/A support' CONFIG_IBMLANA
    fi
-   bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+   dep_bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
       dep_tristate '    Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
@@ -139,16 +150,19 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
         dep_tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
       fi
 
-      tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
+      dep_tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA
       dep_tristate '    CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
       dep_tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
+      if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
+         dep_bool '      New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL
+         bool '      Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO
+      fi
       if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
          tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
          tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
       dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
       dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
-      dep_mbool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
@@ -167,9 +181,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       fi
       dep_tristate '    VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
       dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
-      dep_tristate '    Sun Happy Meal 10/100baseT PCI support' CONFIG_HAPPYMEAL $CONFIG_PCI
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-        bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
+        dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
       fi
       if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ORION" = "y" ]; then
         bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
@@ -180,8 +193,8 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       if [ "$CONFIG_ISA" = "y" -a "$CONFIG_X86" = "y" ]; then
          tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
       fi
-      tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600
-      tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620
+      dep_tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600 $CONFIG_ISA
+      dep_tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620 $CONFIG_ISA
    fi
 fi
 
@@ -198,10 +211,9 @@ dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACE
 if [ "$CONFIG_ACENIC" != "n" ]; then
    bool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
 fi
+dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI
-fi
+dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
 
 endmenu
@@ -211,14 +223,14 @@ if [ "$CONFIG_FDDI" = "y" ]; then
    if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
       tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
    fi
-   tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
+   dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    if [ "$CONFIG_INET" = "y" ]; then
       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
       if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then
-         tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
+         dep_tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER $CONFIG_PCI
          if [ "$CONFIG_ROADRUNNER" != "n" ]; then
            bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
          fi
@@ -226,9 +238,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    fi
 fi
 
-if [ ! "$CONFIG_PARPORT" = "n" ]; then
-   dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
-fi
+dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
index 06231815ba55f5a3bdfcedc702ae6cea98e7b5a3..30840e5d530f9771dfdbd8d337631f53a07beb1c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/net/am79c961.c
  *
- *  by Russell King <rmk@arm.linux.org.uk> 1995-2000.
+ *  by Russell King <rmk@arm.linux.org.uk> 1995-2001.
  *
  * 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
@@ -10,9 +10,9 @@
  * Derived from various things including skeleton.c
  *
  * This is a special driver for the am79c961A Lance chip used in the
- * Intel (formally Digital Equipment Corp) EBSA110 platform.
+ * Intel (formally Digital Equipment Corp) EBSA110 platform.  Please
+ * note that this can not be built as a module (it doesn't make sense).
  */
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -35,7 +35,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/ecard.h>
 
 #define TX_BUFFERS 15
 #define RX_BUFFERS 25
@@ -46,45 +45,42 @@ static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
 
 static unsigned int net_debug = NET_DEBUG;
 
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.02\n";
+static const char version[] =
+       "am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
 
 /* --------------------------------------------------------------------------- */
 
 #ifdef __arm__
-static void
-write_rreg (unsigned long base, unsigned int reg, unsigned short val)
+static void write_rreg(u_long base, u_int reg, u_int val)
 {
        __asm__("str%?h %1, [%2]        @ NET_RAP
                str%?h  %0, [%2, #-4]   @ NET_RDP
-               " : : "r" (val), "r" (reg), "r" (0xf0000464));
+               " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
 
-static inline unsigned short
-read_rreg (unsigned int base_addr, unsigned int reg)
+static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 {
        unsigned short v;
        __asm__("str%?h %1, [%2]        @ NET_RAP
                ldr%?h  %0, [%2, #-4]   @ NET_RDP
-               " : "=r" (v): "r" (reg), "r" (0xf0000464));
+               " : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
        return v;
 }
 
-static inline void
-write_ireg (unsigned long base, unsigned int reg, unsigned short val)
+static inline void write_ireg(u_long base, u_int reg, u_int val)
 {
        __asm__("str%?h %1, [%2]        @ NET_RAP
                str%?h  %0, [%2, #8]    @ NET_IDP
-               " : : "r" (val), "r" (reg), "r" (0xf0000464));
+               " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
 
-#define am_writeword(dev,off,val)\
-       __asm__("str%?h %0, [%1]" : : \
-               "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
+#define am_readword(dev,off)      __raw_readw(ISAMEM_BASE + ((off) << 1))
 
 static inline void
 am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
 {
-       offset = 0xe0000000 + (offset << 1);
+       offset = ISAMEM_BASE + (offset << 1);
        length = (length + 1) & ~1;
        if ((int)buf & 2) {
                __asm__ __volatile__("str%?h    %2, [%0], #4"
@@ -114,23 +110,10 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne
        }
 }
 
-/*
- * This reads a 16-bit quantity in little-endian
- * mode from the am79c961 buffer.
- */
-static inline unsigned short am_readword(struct net_device *dev, u_int off)
-{
-       unsigned long address = 0xe0000000 + (off << 1);
-       unsigned short val;
-
-       __asm__("ldr%?h %0, [%1]" : "=r" (val): "r" (address));
-       return val;
-}
-
 static inline void
 am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
 {
-       offset = 0xe0000000 + (offset << 1);
+       offset = ISAMEM_BASE + (offset << 1);
        length = (length + 1) & ~1;
        if ((int)buf & 2) {
                unsigned int tmp;
@@ -274,12 +257,7 @@ am79c961_init_for_open(struct net_device *dev)
 }
 
 /*
- * Open/initialize the board.  This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * Open/initialize the board.
  */
 static int
 am79c961_open(struct net_device *dev)
@@ -322,8 +300,7 @@ am79c961_close(struct net_device *dev)
 }
 
 /*
- * Get the current statistics. This may be called with the card open or
- * closed.
+ * Get the current statistics.
  */
 static struct net_device_stats *am79c961_getstats (struct net_device *dev)
 {
@@ -367,7 +344,7 @@ static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
 }
 
 /*
- * Set or clear promiscuous/multicast mode filter for this adaptor.
+ * Set or clear promiscuous/multicast mode filter for this adapter.
  */
 static void am79c961_setmulticastlist (struct net_device *dev)
 {
@@ -478,10 +455,8 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
         * then the tx ring is full and we can't add another
         * packet.
         */
-       if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) {
-               printk(KERN_DEBUG"tx ring full, stopping queue\n");
+       if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
                netif_stop_queue(dev);
-       }
 
        dev_kfree_skb(skb);
 
@@ -557,9 +532,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
        do {
                u_int hdraddr;
                u_int status;
-int bufnum;
 
-bufnum = priv->txtail;
                hdraddr = priv->txhdr + (priv->txtail << 3);
                status = am_readword (dev, hdraddr + 2);
                if (status & TMD_OWN)
@@ -654,7 +627,6 @@ static int __init am79c961_init(void)
        if (!dev)
                goto out;
 
-       SET_MODULE_OWNER(dev);
        priv = dev->priv;
 
        /*
@@ -668,7 +640,7 @@ static int __init am79c961_init(void)
        /*
         * Reset the device.
         */
-       inb((dev->base_addr + NET_RESET) >> 1);
+       inb(dev->base_addr + NET_RESET);
        udelay(5);
 
        /*
@@ -676,21 +648,20 @@ static int __init am79c961_init(void)
         * ether address.
         */
        ret = -ENODEV;
-       if (inb(dev->base_addr >> 1) != 0x08 ||
-           inb((dev->base_addr >> 1) + 1) != 00 ||
-           inb((dev->base_addr >> 1) + 2) != 0x2b)
+       if (inb(dev->base_addr) != 0x08 ||
+           inb(dev->base_addr + 2) != 0x00 ||
+           inb(dev->base_addr + 4) != 0x2b)
                goto nodev;
 
        if (!request_region(dev->base_addr, 0x18, dev->name))
                goto nodev;
 
        am79c961_banner();
-       printk(KERN_INFO "%s: am79c961 found at %08lx, IRQ%d, ether address ",
-               dev->name, dev->base_addr, dev->irq);
+       printk(KERN_INFO "%s: ether address ", dev->name);
 
        /* Retrive and print the ethernet address. */
        for (i = 0; i < 6; i++) {
-               dev->dev_addr[i] = inb((dev->base_addr >> 1) + i) & 0xff;
+               dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
                printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
        }
 
@@ -715,4 +686,4 @@ out:
        return ret;
 }
 
-module_init(am79c961_init);
+__initcall(am79c961_init);
index 89f33cc04781c221c062ddf5a1c1c76461cce122..acd15efa937ed8db20bc55e4808ac11115d2c2cc 100644 (file)
@@ -255,22 +255,26 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
 static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
         struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
+        struct ipddp_route rcp;
 
         if(!capable(CAP_NET_ADMIN))
                 return -EPERM;
 
+       if(copy_from_user(&rcp, rt, sizeof(rcp)))
+               return -EFAULT;
+
         switch(cmd)
         {
                case SIOCADDIPDDPRT:
-                        return (ipddp_create(rt));
+                        return (ipddp_create(&rcp));
 
                 case SIOCFINDIPDDPRT:
-                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
+                        if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
                                 return -EFAULT;
                         return 0;
 
                 case SIOCDELIPDDPRT:
-                        return (ipddp_delete(rt));
+                        return (ipddp_delete(&rcp));
 
                 default:
                         return -EINVAL;
index f5e390fe4a93bec5ac727abe16635b5b54f70489..d66e2b462cc7b54f17c20752d3cfeaad670f2fdd 100644 (file)
 #include <asm/io.h>
 #include <asm/dma.h>
 
+#if BITS_PER_LONG == 64
+#error FIXME: driver does not support 64-bit platforms
+#endif
+
 
 /* Board/System/Debug information/definition ---------------- */
 #define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
index f4fc6c49998ea332215621d10e6eab21da8057e5..73d6ee6bfd6bb96d83b3f486f30ff0a43a7485a5 100644 (file)
@@ -1633,38 +1633,44 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        u_long iobase = dev->base_addr;
        int i, j, status = 0;
        u_char csr;
-       union {
+       union ewrk3_addr {
                u_char addr[HASH_TABLE_LEN * ETH_ALEN];
                u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-       } tmp;
+       };
+       
+       union ewrk3_addr *tmp;
+
+       tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
+       if(tmp==NULL)
+               return -ENOMEM;
 
        switch (ioc->cmd) {
        case EWRK3_GET_HWADDR:  /* Get the hardware address */
                for (i = 0; i < ETH_ALEN; i++) {
-                       tmp.addr[i] = dev->dev_addr[i];
+                       tmp->addr[i] = dev->dev_addr[i];
                }
                ioc->len = ETH_ALEN;
-               if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
                        status = -EFAULT;
-                       break;
-               }
+               break;
+               
        case EWRK3_SET_HWADDR:  /* Set the hardware address */
                if (capable(CAP_NET_ADMIN)) {
-                               csr = inb(EWRK3_CSR);
-                               csr |= (CSR_TXD | CSR_RXD);
-                               outb(csr, EWRK3_CSR);   /* Disable the TX and RX */
+                       csr = inb(EWRK3_CSR);
+                       csr |= (CSR_TXD | CSR_RXD);
+                       outb(csr, EWRK3_CSR);   /* Disable the TX and RX */
 
-                               if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) {
-                                       status = -EFAULT;
-                                       break;
-                               }
-                               for (i = 0; i < ETH_ALEN; i++) {
-                                       dev->dev_addr[i] = tmp.addr[i];
-                                       outb(tmp.addr[i], EWRK3_PAR0 + i);
-                               }
+                       if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
+                               status = -EFAULT;
+                               break;
+                       }
+                       for (i = 0; i < ETH_ALEN; i++) {
+                               dev->dev_addr[i] = tmp->addr[i];
+                               outb(tmp->addr[i], EWRK3_PAR0 + i);
+                       }
 
-                               csr &= ~(CSR_TXD | CSR_RXD);    /* Enable the TX and RX */
-                               outb(csr, EWRK3_CSR);
+                       csr &= ~(CSR_TXD | CSR_RXD);    /* Enable the TX and RX */
+                       outb(csr, EWRK3_CSR);
                } else {
                        status = -EPERM;
                }
@@ -1690,10 +1696,6 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                        status = -EPERM;
                }
 
-               break;
-       case EWRK3_SAY_BOO:     /* Say "Boo!" to the kernel log file */
-               printk("%s: Boo!\n", dev->name);
-
                break;
        case EWRK3_GET_MCA:     /* Get the multicast address table */
                spin_lock_irq(&lp->hw_lock);
@@ -1701,22 +1703,22 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                        outb(0, EWRK3_IOPR);
                        outw(PAGE0_HTE, EWRK3_PIR1);
                        for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-                               tmp.addr[i] = inb(EWRK3_DATA);
+                               tmp->addr[i] = inb(EWRK3_DATA);
                        }
                } else {
                        outb(0, EWRK3_MPR);
-                       isa_memcpy_fromio(tmp.addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
+                       isa_memcpy_fromio(tmp->addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
                }
                spin_unlock_irq(&lp->hw_lock);
 
                ioc->len = (HASH_TABLE_LEN >> 3);
-               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
                        status = -EFAULT;
 
                break;
        case EWRK3_SET_MCA:     /* Set a multicast address */
                if (capable(CAP_NET_ADMIN)) {
-                       if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) {
+                       if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
                                status = -EFAULT;
                                break;
                        }
@@ -1764,18 +1766,18 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
                break;
        case EWRK3_GET_CSR:     /* Get the CSR Register contents */
-               tmp.addr[0] = inb(EWRK3_CSR);
+               tmp->addr[0] = inb(EWRK3_CSR);
                ioc->len = 1;
-               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
                        status = -EFAULT;
                break;
        case EWRK3_SET_CSR:     /* Set the CSR Register contents */
                if (capable(CAP_NET_ADMIN)) {
-                       if (copy_from_user(tmp.addr, ioc->data, 1)) {
+                       if (copy_from_user(tmp->addr, ioc->data, 1)) {
                                status = -EFAULT;
                                break;
                        }
-                       outb(tmp.addr[0], EWRK3_CSR);
+                       outb(tmp->addr[0], EWRK3_CSR);
                } else {
                        status = -EPERM;
                }
@@ -1784,15 +1786,15 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        case EWRK3_GET_EEPROM:  /* Get the EEPROM contents */
                if (capable(CAP_NET_ADMIN)) {
                        for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-                               tmp.val[i] = (short) Read_EEPROM(iobase, i);
+                               tmp->val[i] = (short) Read_EEPROM(iobase, i);
                        }
                        i = EEPROM_MAX;
-                       tmp.addr[i++] = inb(EWRK3_CMR);         /* Config/Management Reg. */
+                       tmp->addr[i++] = inb(EWRK3_CMR);                /* Config/Management Reg. */
                        for (j = 0; j < ETH_ALEN; j++) {
-                               tmp.addr[i++] = inb(EWRK3_PAR0 + j);
+                               tmp->addr[i++] = inb(EWRK3_PAR0 + j);
                        }
                        ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
-                       if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+                       if (copy_to_user(ioc->data, tmp->addr, ioc->len))
                                status = -EFAULT;
                } else {
                        status = -EPERM;
@@ -1801,12 +1803,12 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                break;
        case EWRK3_SET_EEPROM:  /* Set the EEPROM contents */
                if (capable(CAP_NET_ADMIN)) {
-                       if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) {
+                       if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) {
                                status = -EFAULT;
                                break;
                        }
                        for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-                               Write_EEPROM(tmp.val[i], iobase, i);
+                               Write_EEPROM(tmp->val[i], iobase, i);
                        }
                } else {
                        status = -EPERM;
@@ -1814,9 +1816,9 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
                break;
        case EWRK3_GET_CMR:     /* Get the CMR Register contents */
-               tmp.addr[0] = inb(EWRK3_CMR);
+               tmp->addr[0] = inb(EWRK3_CMR);
                ioc->len = 1;
-               if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+               if (copy_to_user(ioc->data, tmp->addr, ioc->len))
                        status = -EFAULT;
                break;
        case EWRK3_SET_TX_CUT_THRU:     /* Set TX cut through mode */
@@ -1838,7 +1840,7 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        default:
                status = -EOPNOTSUPP;
        }
-
+       kfree(tmp);
        return status;
 }
 
index 1ad314e6e7417c90e2af3f54bd3491385cca88df..8e16c1b68c6e1e67726ffe0148a8ca12db67c43d 100644 (file)
@@ -886,7 +886,7 @@ static int netdev_open(struct net_device *dev)
           1 1 1   256
           Wait the specified 50 PCI cycles after a reset by initializing
           Tx and Rx queues and the address filter list. */
-#if defined(__powerpc__)
+#if defined(__powerpc__) || defined(__sparc__)
 // 89/9/1 modify, 
 //   np->bcrvalue=0x04 | 0x0x38;  /* big-endian, 256 burst length */
        np->bcrvalue = 0x04 | 0x10;     /* big-endian, tx 8 burst length */
@@ -1166,19 +1166,17 @@ static void tx_timeout(struct net_device *dev)
        printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
               " resetting...\n", dev->name, readl(ioaddr + ISR));
 
-#ifndef __alpha__
        {
                int i;
 
-               printk(KERN_DEBUG "  Rx ring %8.8x: ", (int) np->rx_ring);
+               printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
                        printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
-               printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int) np->tx_ring);
+               printk("\n" KERN_DEBUG "  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
                        printk(" %4.4x", np->tx_ring[i].status);
                printk("\n");
        }
-#endif
 
        /* Perhaps we should reinitialize the hardware here.  Just trigger a
           Tx demand for now. */
index 0b90edaf6d33af8032ac3d74261260302b7ffc4d..12daac3c8e4d7801e0b366fe43a0883dec1068a0 100644 (file)
@@ -166,7 +166,7 @@ static inline int dev_is_ethdev(struct net_device *dev)
  */
 static int bpq_check_devices(struct net_device *dev)
 {
-       struct bpqdev *bpq, *bpq_prev;
+       struct bpqdev *bpq, *bpq_prev, *bpq_next;
        int result = 0;
        unsigned long flags;
 
@@ -175,7 +175,8 @@ static int bpq_check_devices(struct net_device *dev)
 
        bpq_prev = NULL;
 
-       for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) {
+       for (bpq = bpq_devices; bpq != NULL; bpq = bpq_next) {
+               bpq_next = bpq->next;
                if (!dev_get(bpq->ethname)) {
                        if (bpq_prev)
                                bpq_prev->next = bpq->next;
@@ -192,8 +193,8 @@ static int bpq_check_devices(struct net_device *dev)
                        unregister_netdevice(&bpq->axdev);
                        kfree(bpq);
                }
-
-               bpq_prev = bpq;
+               else
+                       bpq_prev = bpq;
        }
 
        restore_flags(flags);
index 92d468aa8b04508b97283a622130719faa9a48ef..8114827e5350a69b497234abcb297e40af5eca15 100644 (file)
@@ -216,7 +216,7 @@ static struct net_device_stats * scc_net_get_stats(struct net_device *dev);
 
 static unsigned char SCC_DriverName[] = "scc";
 
-static struct irqflags { unsigned char used : 1; } Ivec[16];
+static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS];
        
 static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS];  /* information per channel */
 
@@ -1484,7 +1484,7 @@ static void z8530_init(void)
        printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
        
        flag=" ";
-       for (k = 0; k < 16; k++)
+       for (k = 0; k < NR_IRQS; k++)
                if (Ivec[k].used) 
                {
                        printk("%s%d", flag, k);
@@ -1764,6 +1764,9 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
                        if (hwcfg.irq == 2) hwcfg.irq = 9;
 
+                       if (hwcfg.irq <0 || hwcfg.irq > NR_IRQS)
+                               return -EINVAL;
+                               
                        if (!Ivec[hwcfg.irq].used && hwcfg.irq)
                        {
                                if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))
@@ -2162,7 +2165,7 @@ static void __exit scc_cleanup_driver(void)
                }
        }
        
-       for (k=0; k < 16 ; k++)
+       for (k=0; k < NR_IRQS ; k++)
                if (Ivec[k].used) free_irq(k, NULL);
                
        if (Vector_Latch)
index 24a586740c32e54deda63ae757323a1e15cfd1e4..045e7e053402f3c4695a86f7c487a82c442e7053 100644 (file)
@@ -299,6 +299,8 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
 
 #ifdef __i386__
 
+#include <asm/msr.h>
+
 /*
  * only do 32bit cycle counter arithmetic; we hope we won't overflow.
  * in fact, overflowing modems would require over 2THz CPU clock speeds :-)
@@ -307,10 +309,10 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
 #define time_exec(var,cmd)                                              \
 ({                                                                      \
        if (cpu_has_tsc) {                                              \
-               unsigned int cnt1, cnt2, cnt3;                          \
-               __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3));  \
+               unsigned int cnt1, cnt2;                                \
+               rdtscl(cnt1);                                           \
                cmd;                                                    \
-               __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3));  \
+               rdtscl(cnt2);                                           \
                var = cnt2-cnt1;                                        \
        } else {                                                        \
                cmd;                                                    \
index 19840c491bd7766124d5d56c1bdd0b551319eea6..6d94d6da4a463c9971ca06577888dd72c4bf8e96 100644 (file)
@@ -172,8 +172,10 @@ static int wss_set_codec_fmt(struct net_device *dev, struct sm_state *sm, unsign
                /* MCE and interface config reg */
                write_codec(dev, 0x49, fdx ? 0x8 : 0xc);
        outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */
-       if (SCSTATE->crystal && !fullcalib)
+       if (SCSTATE->crystal && !fullcalib) {
+               restore_flags(flags);
                return 0;
+       }
        /*
         * wait for ACI start
         */
index c5b3db54acc1c4a02d6d895bb9c0b92ba24e1c36..745c4090bb492b1840e062fa3d99b1dc84307f56 100644 (file)
@@ -833,18 +833,16 @@ static void tx_timeout(struct net_device *dev)
        printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
                   " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));
 
-#ifndef __alpha__
        {
                int i;
-               printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
+               printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
                        printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);
-               printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
+               printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
                        printk(" %4.4x", np->tx_ring[i].cmd_status);
                printk("\n");
        }
-#endif
        spin_lock_irq(&np->lock);
        natsemi_reset(dev);
        drain_ring(dev);
index 27b24a2f6fcaa0ec8ef51e23597262ffe87b556f..ad2c001a3b978964b47ce632a72e61dd03058b3d 100644 (file)
@@ -283,7 +283,7 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
                                shaper->dev->name,newskb->priority);
                dev_queue_xmit(newskb);
 
-                shaper->stats.tx_bytes+=newskb->len;
+                shaper->stats.tx_bytes += skb->len;
                shaper->stats.tx_packets++;
 
                 if(sh_debug)
index d6e104c06de0fc646517d1a6a6bb2e1ec63fddf4..3fb384b1116d86110f80afdf0618810f88dd03d7 100644 (file)
@@ -1002,7 +1002,7 @@ sis900_init_rx_ring(struct net_device *net_dev)
 static void sis630_set_eq(struct net_device *net_dev, u8 revision)
 {
        struct sis900_private *sis_priv = net_dev->priv;
-       u16 reg14h, eq_value, max_value=0, min_value=0;
+       u16 reg14h, eq_value=0, max_value=0, min_value=0;
        u8 host_bridge_rev;
        int i, maxcount=10;
        struct pci_dev *dev=NULL;
index 4f4170e1cdaf05ca056630c1d6e639d7cc0a4da5..57fed91b5ae064c9f6bc6c6fc8371f79aad2fff5 100644 (file)
@@ -740,18 +740,16 @@ static void tx_timeout(struct net_device *dev)
        printk(KERN_WARNING "%s: Transmit timed out, status %2.2x,"
                   " resetting...\n", dev->name, readb(ioaddr + TxStatus));
 
-#ifndef __alpha__
        {
                int i;
-               printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
+               printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
                        printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-               printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
+               printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
                        printk(" %4.4x", np->tx_ring[i].status);
                printk("\n");
        }
-#endif
 
        /* Perhaps we should reinitialize the hardware here. */
        dev->if_port = 0;
index 62255808d32576eb99a0ecf24657a51d1a0e2e4a..4b7315ed6a0bb7f493102cce1949682a1cb951ec 100644 (file)
  *    1. Multicast support.
  */
 
-#if defined(__alpha__) || defined(__ia64__)
-#error FIXME: driver does not support 64-bit platforms
-#endif
-
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/skbuff.h>
 #include <linux/trdevice.h>
 
+#if BITS_PER_LONG == 64
+#error FIXME: driver does not support 64-bit platforms
+#endif
+
 #include "smctr.h"               /* Our Stuff */
 #include "smctr_firmware.h"      /* SMC adapter firmware */
 
index e6a2837b846a3f93485d4200abc3eb41f7f59836..8c367b5cca023752078e67ee3fbd86d9b485baa9 100644 (file)
@@ -487,15 +487,18 @@ static int MIXCOM_open(struct net_device *dev)
        struct mixcom_privdata *hw = ch->HW_privdata;
        struct proc_dir_entry *procfile = ch->procdir->subdir;
        unsigned long flags; 
+       int ret = -ENODEV;
 
-       if (!dev->base_addr || !dev->irq) return -ENODEV;
+       if (!dev->base_addr || !dev->irq)
+               goto err_ret;
 
 
        if(hw->channel==1) {
                if(!TWIN(dev) || !(COMX_CHANNEL(TWIN(dev))->init_status & 
                    IRQ_ALLOCATED)) {
                        printk(KERN_ERR "%s: channel 0 not yet initialized\n",dev->name);
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       goto err_ret;
                }
        }
 
@@ -503,28 +506,29 @@ static int MIXCOM_open(struct net_device *dev)
        /* Is our hw present at all ? Not checking for channel 0 if it is already 
           open */
        if(hw->channel!=0 || !(ch->init_status & IRQ_ALLOCATED)) {
-               if (check_region(dev->base_addr, MIXCOM_IO_EXTENT)) {
-                       return -EAGAIN;
+               if (!request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name)) {
+                       ret = -EAGAIN;
+                       goto err_ret;
                }
                if (mixcom_probe(dev)) {
-                       return -ENODEV;
+                       ret = -ENODEV;
+                       goto err_release_region;
                }
        }
 
-       save_flags(flags); cli();
-
-       if(hw->channel==1) {
-               request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
-       } 
-
        if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
                if (request_irq(dev->irq, MIXCOM_interrupt, 0, 
                    dev->name, (void *)dev)) {
                        printk(KERN_ERR "MIXCOM: unable to obtain irq %d\n", dev->irq);
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       goto err_release_region;
                }
+       }
+
+       save_flags(flags); cli();
+
+       if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
                ch->init_status|=IRQ_ALLOCATED;
-               request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
                mixcom_board_on(dev);
        }
 
@@ -560,6 +564,13 @@ static int MIXCOM_open(struct net_device *dev)
        }
 
        return 0;
+       
+err_restore_flags:
+       restore_flags(flags);
+err_release_region:
+       release_region(dev->base_addr, MIXCOM_IO_EXTENT);
+err_ret:
+       return ret;
 }
 
 static int MIXCOM_close(struct net_device *dev)
index a1f6c8bdc8f26999bec4dab98045d074b0bd82f5..124c66e102f3b7aa21c57efc39e01be893b3f0e8 100644 (file)
@@ -503,6 +503,8 @@ static int fr_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (dev != fr->master) {
                struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+               if (!newskb)
+                       return -ENOMEM;
                newskb->dev=fr->master;
                dev_queue_xmit(newskb);
                ch->stats.tx_bytes += skb->len;
@@ -701,7 +703,7 @@ static int fr_write_proc(struct file *file, const char *buffer,
        } else {
                printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n", 
                        entry->name);
-               return -EBADF;
+               count = -EBADF;
        }
 
        free_page((unsigned long)page);
@@ -960,30 +962,27 @@ static int dlci_dump(struct net_device *dev)
 }
 
 static struct comx_protocol fr_master_protocol = {
-       "frad", 
-       VERSION,
-       ARPHRD_FRAD, 
-       fr_master_init, 
-       fr_exit, 
-       NULL 
+       name:           "frad", 
+       version:        VERSION,
+       encap_type:     ARPHRD_FRAD, 
+       line_init:      fr_master_init, 
+       line_exit:      fr_exit, 
 };
 
 static struct comx_protocol fr_slave_protocol = {
-       "ietf-ip", 
-       VERSION,
-       ARPHRD_DLCI, 
-       fr_slave_init, 
-       fr_exit, 
-       NULL 
+       name:           "ietf-ip", 
+       version:        VERSION,
+       encap_type:     ARPHRD_DLCI, 
+       line_init:      fr_slave_init, 
+       line_exit:      fr_exit, 
 };
 
 static struct comx_hardware fr_dlci = { 
-       "dlci", 
-       VERSION,
-       dlci_init, 
-       dlci_exit, 
-       dlci_dump, 
-       NULL 
+       name:           "dlci", 
+       version:        VERSION,
+       hw_init:        dlci_init, 
+       hw_exit:        dlci_exit, 
+       hw_dump:        dlci_dump, 
 };
 
 #ifdef MODULE
index 96b921ee0591447d8aed2dec4e1bc21487b4e78f..6ce3d7a5c313fbc716dcbe9fc8720ec55af5ed36 100644 (file)
@@ -1046,15 +1046,15 @@ static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d)
            __get_user(code, &(d->code)))
                return -EFAULT;
 
-       if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
+       if (addr < 0 || addr > COSA_MAX_FIRMWARE_SIZE)
                return -EINVAL;
-       if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
+       if (len < 0 || len > COSA_MAX_FIRMWARE_SIZE)
                return -EINVAL;
 
        /* If something fails, force the user to reset the card */
        cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_DOWNLOAD);
 
-       if ((i=download(cosa, d->code, len, addr)) < 0) {
+       if ((i=download(cosa, code, len, addr)) < 0) {
                printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n",
                        cosa->num, i);
                return -EIO;
index a67fcfb78ad6795dac5888d40d9a006d2f4e460d..7677f2941acd0de53ccba33332734c165e4770f9 100644 (file)
@@ -89,7 +89,7 @@ static inline int dev_is_ethdev(struct net_device *dev)
  */
 static int lapbeth_check_devices(struct net_device *dev)
 {
-       struct lapbethdev *lapbeth, *lapbeth_prev;
+       struct lapbethdev *lapbeth, *lapbeth_prev, *lapbeth_next;
        int result = 0;
        unsigned long flags;
 
@@ -98,7 +98,8 @@ static int lapbeth_check_devices(struct net_device *dev)
 
        lapbeth_prev = NULL;
 
-       for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) {
+       for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth_next) {
+               lapbeth_next = lapbeth->next;
                if (!dev_get(lapbeth->ethname)) {
                        if (lapbeth_prev)
                                lapbeth_prev->next = lapbeth->next;
@@ -112,8 +113,8 @@ static int lapbeth_check_devices(struct net_device *dev)
                        dev_put(lapbeth->ethdev);
                        kfree(lapbeth);
                }
-
-               lapbeth_prev = lapbeth;
+               else
+                       lapbeth_prev = lapbeth;
        }
 
        restore_flags(flags);
index a87f8b249023288c19c3ada045fe416317c9bff1..f63c3898102cf5242433c40fca8cdda3f06354c5 100644 (file)
@@ -507,7 +507,12 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
                             break;
                     }
                     
-                    LMC_COPY_FROM_USER(data, xc.data, xc.len);
+                    if(copy_from_user(data, xc.data, xc.len))
+                    {
+                       kfree(data);
+                       ret = -ENOMEM;
+                       break;
+                    }
 
                     printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
 
index 7aa1fa29b95ad84294e682c2c6e3e8fe3d52d7b0..7a08f6f6a7fb0d02376aab05fbe4853acec17a17 100644 (file)
@@ -147,7 +147,7 @@ static char *sppp_lcp_type_name (u8 type);
 static char *sppp_ipcp_type_name (u8 type);
 static void sppp_print_bytes (u8 *p, u16 len);
 
-static int debug = 0;
+static int debug;
 
 
 /*
@@ -518,8 +518,10 @@ badreq:
                }
                /* Send Configure-Ack packet. */
                sp->pp_loopcnt = 0;
-               sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
-                               h->ident, len-4, h+1);
+               if (sp->lcp.state != LCP_STATE_OPENED) {
+                       sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+                                       h->ident, len-4, h+1);
+               }
                /* Change the state. */
                switch (sp->lcp.state) {
                case LCP_STATE_CLOSED:
@@ -535,7 +537,9 @@ badreq:
                        sp->ipcp.state = IPCP_STATE_CLOSED;
                        /* Initiate renegotiation. */
                        sppp_lcp_open (sp);
-                       /* An ACK has already been sent. */
+                       /* Send ACK after our REQ in attempt to break loop */
+                       sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+                                       h->ident, len-4, h+1);
                        sp->lcp.state = LCP_STATE_ACK_SENT;
                        break;
                }
@@ -1388,25 +1392,21 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
        return 0;
 }
 
-
-struct packet_type sppp_packet_type=
-{
-       0,
-       NULL,
-       sppp_rcv,
-       NULL,
-       NULL
+struct packet_type sppp_packet_type = {
+       type:   __constant_htons(ETH_P_WAN_PPP),
+       func:   sppp_rcv,
 };
 
-
+static const char banner[] __initdata = 
+       KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"
+       KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "
+                 "Jan \"Yenya\" Kasprzak.\n";
 
 static int __init sync_ppp_init(void)
 {
        if(debug)
                debug=PP_DEBUG;
-       printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
-       printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
-       sppp_packet_type.type=htons(ETH_P_WAN_PPP);     
+       printk(banner);
        dev_add_pack(&sppp_packet_type);
        return 0;
 }
index 0e12d07007d8f7febae1e8ef158ce8cac4201386..ab30926e6f2d6dde0212a57130a4ba3c0409f1f3 100644 (file)
@@ -839,7 +839,7 @@ static void init_registers(struct net_device *dev)
                C000    32  longwords           0400 4 longwords
           Wait the specified 50 PCI cycles after a reset by initializing
           Tx and Rx queues and the address filter list. */
-#if defined(__powerpc__)               /* Big-endian */
+#if defined(__powerpc__) || defined(__sparc__)         /* Big-endian */
        writel(0x00100080 | 0xE010, ioaddr + PCIBusCfg);
 #elif defined(__alpha__)
        writel(0xE010, ioaddr + PCIBusCfg);
@@ -884,13 +884,12 @@ static void tx_timeout(struct net_device *dev)
        printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
                   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
 
-#ifndef __alpha__
        {
                int i;
-               printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
+               printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
                        printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-               printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
+               printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
                        printk(" %8.8x", np->tx_ring[i].status);
                printk("\n");
@@ -899,7 +898,6 @@ static void tx_timeout(struct net_device *dev)
                                np->cur_tx, np->dirty_tx, np->tx_full,np->tx_q_bytes);
        printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C));
 
-#endif
        spin_lock_irq(&np->lock);
        /*
         * Under high load dirty_tx and the internal tx descriptor pointer
@@ -1376,7 +1374,6 @@ static int netdev_close(struct net_device *dev)
 {
        long ioaddr = dev->base_addr;
        struct netdev_private *np = dev->priv;
-       int i;
 
        netif_stop_queue(dev);
 
@@ -1399,6 +1396,8 @@ static int netdev_close(struct net_device *dev)
 
 #ifdef __i386__
        if (debug > 2) {
+               int i;
+
                printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
                           (int)np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
index b07d83358d98b948927c3d6ed2e88727b016d376..735c0d17eeb4c6aa036df815849c2584faf1bfbe 100644 (file)
@@ -574,7 +574,7 @@ static int __init nubus_get_vidnames(struct nubus_board* board,
                /* Now clobber the whole thing */
                if (size > sizeof(mode) - 1)
                        size = sizeof(mode) - 1;
-               memset(&mode, sizeof(mode), 0);
+               memset(&mode, 0, sizeof(mode));
                nubus_get_rsrc_mem(&mode, &ent, size);
                printk (KERN_INFO "      %02X: (%02X) %s\n", ent.type,
                        mode.id, mode.name);
index c4673d9ae094876b43300ad8eddaa35ea6769a43..3ab0811a8e57976f0d23f93e576c96be8e54ee4f 100644 (file)
                  Make tw_setfeature() call with interrupts disabled.
                  Register interrupt handler before enabling interrupts.
                  Clear attention interrupt before draining aen queue.
+   1.02.00.005 - Allocate bounce buffers and custom queue depth for raid5 for
+                 6000 and 5000 series controllers.
+                 Reduce polling mdelays causing problems on some systems.
+                 Fix use_sg = 1 calculation bug.
+                 Check for scsi_register returning NULL.
+                 Add aen count to /proc/scsi/3w-xxxx.
+                 Remove aen code unit masking in tw_aen_complete().
+   1.02.00.006 - Remove unit from printk in tw_scsi_eh_abort(), causing
+                 possible oops.
+                 Fix possible null pointer dereference in tw_scsi_queue()
+                 if done function pointer was invalid.
+   1.02.00.007 - Fix possible null pointer dereferences in tw_ioctl().
+                 Remove check for invalid done function pointer from
+                 tw_scsi_queue().
 */
 
 #include <linux/module.h>
@@ -121,7 +135,7 @@ static struct notifier_block tw_notifier = {
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.004";
+char *tw_driver_version="1.02.00.007";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -131,7 +145,7 @@ int tw_device_extension_count = 0;
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) 
 {
        TW_Param *param;
-       unsigned short aen, aen_code;
+       unsigned short aen;
 
        if (tw_dev->alignment_virtual_address[request_id] == NULL) {
                printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
@@ -139,10 +153,9 @@ int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id)
        }
        param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
        aen = *(unsigned short *)(param->data);
-       aen_code = (aen & 0x0ff);
-       dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen_code);
+       dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
        /* Now queue the code */
-       tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;
+       tw_dev->aen_queue[tw_dev->aen_tail] = aen;
        if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
                tw_dev->aen_tail = TW_Q_START;
        } else {
@@ -241,7 +254,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
     
                /* Now poll for completion */
                for (i=0;i<imax;i++) {
-                       mdelay(10);
+                       mdelay(5);
                        status_reg_value = inl(status_reg_addr);
                        if (tw_check_bits(status_reg_value)) {
                                printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
@@ -437,13 +450,21 @@ int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, in
                return 1;
        }
 
-       if (which == 0) {
+       switch(which) {
+       case 0:
                tw_dev->command_packet_virtual_address[request_id] = virt_addr;
-               tw_dev->command_packet_physical_address[request_id] = 
-               virt_to_bus(virt_addr);
-       } else {
+               tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
+               break;
+       case 1:
                tw_dev->alignment_virtual_address[request_id] = virt_addr;
                tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
+               break;
+       case 2:
+               tw_dev->bounce_buffer[request_id] = virt_addr;
+               break;
+       default:
+               printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+               return 1;
        }
        return 0;
 } /* End tw_allocate_memory() */
@@ -709,8 +730,8 @@ int tw_findcards(Scsi_Host_Template *tw_host)
 
                /* Register the card with the kernel SCSI layer */
                        host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-                       if( host == NULL)
-                       {
+                       if (host == NULL) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
                                release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
                                tw_free_device_extension(tw_dev);
                                kfree(tw_dev);
@@ -788,6 +809,9 @@ void tw_free_device_extension(TW_Device_Extension *tw_dev)
 
                if (tw_dev->alignment_virtual_address[i])
                        kfree(tw_dev->alignment_virtual_address[i]);
+
+               if (tw_dev->bounce_buffer[i])
+                       kfree(tw_dev->bounce_buffer[i]);
        }
 } /* End tw_free_device_extension() */
 
@@ -853,7 +877,7 @@ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits)
        /* Poll for completion */
        imax = TW_POLL_MAX_RETRIES;
        for (i=0;i<imax;i++) {
-               mdelay(10);
+               mdelay(5);
                status_reg_value = inl(status_reg_addr);
                if (tw_check_bits(status_reg_value)) {
                        printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
@@ -909,8 +933,10 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
                tw_dev->aen_queue[i] = 0;
        }
 
-       for (i=0;i<TW_MAX_UNITS;i++)
+       for (i=0;i<TW_MAX_UNITS;i++) {
                tw_dev->is_unit_present[i] = 0;
+               tw_dev->is_raid_five[i] = 0;
+       }
 
        tw_dev->num_units = 0;
        tw_dev->num_aborts = 0;
@@ -928,6 +954,8 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
        tw_dev->aen_tail = 0;
        tw_dev->sector_count = 0;
        tw_dev->max_sector_count = 0;
+       tw_dev->aen_count = 0;
+       tw_dev->num_raid_five = 0;
        spin_lock_init(&tw_dev->tw_lock);
        tw_dev->flags = 0;
        return 0;
@@ -940,13 +968,14 @@ int tw_initialize_units(TW_Device_Extension *tw_dev)
        unsigned char request_id = 0;
        TW_Command *command_packet;
        TW_Param *param;
-       int i, imax, num_units = 0;
+       int i, j, imax, num_units = 0, num_raid_five = 0;
        u32 status_reg_addr, status_reg_value;
        u32 command_que_addr, command_que_value;
        u32 response_que_addr;
        TW_Response_Queue response_queue;
        u32 param_value;
        unsigned char *is_unit_present;
+       unsigned char *raid_level;
 
        dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
 
@@ -1001,7 +1030,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev)
        /* Poll for completion */
        imax = TW_POLL_MAX_RETRIES;
        for(i=0; i<imax; i++) {
-               mdelay(10);
+               mdelay(5);
                status_reg_value = inl(status_reg_addr);
                if (tw_check_bits(status_reg_value)) {
                        printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
@@ -1052,6 +1081,110 @@ int tw_initialize_units(TW_Device_Extension *tw_dev)
                printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n");
                return 1;
        }
+
+       /* Find raid 5 arrays */
+       for (j=0;j<TW_MAX_UNITS;j++) {
+               if (tw_dev->is_unit_present[j] == 0)
+                       continue;
+               command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+               if (command_packet == NULL) {
+                       printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
+                       return 1;
+               }
+               memset(command_packet, 0, sizeof(TW_Sector));
+               command_packet->byte0.opcode      = TW_OP_GET_PARAM;
+               command_packet->byte0.sgl_offset  = 2;
+               command_packet->size              = 4;
+               command_packet->request_id        = request_id;
+               command_packet->byte3.unit        = 0;
+               command_packet->byte3.host_id     = 0;
+               command_packet->status            = 0;
+               command_packet->flags             = 0;
+               command_packet->byte6.block_count = 1;
+
+               /* Now setup the param */
+               if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+                       printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
+                       return 1;
+               }
+               param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+               memset(param, 0, sizeof(TW_Sector));
+               param->table_id = 0x300+j; /* unit summary table */
+               param->parameter_id = 0x6; /* unit descriptor */
+               param->parameter_size_bytes = 0xc;
+               param_value = tw_dev->alignment_physical_address[request_id];
+               if (param_value == 0) {
+                       printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
+                       return 1;
+               }
+
+               command_packet->byte8.param.sgl[0].address = param_value;
+               command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+               /* Post the command packet to the board */
+               command_que_value = tw_dev->command_packet_physical_address[request_id];
+               if (command_que_value == 0) {
+                       printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
+                       return 1;
+               }
+               outl(command_que_value, command_que_addr);
+
+               /* Poll for completion */
+               imax = TW_POLL_MAX_RETRIES;
+               for(i=0; i<imax; i++) {
+                       mdelay(5);
+                       status_reg_value = inl(status_reg_addr);
+                       if (tw_check_bits(status_reg_value)) {
+                               printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
+                               return 1;
+                       }
+                       if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+                               response_queue.value = inl(response_que_addr);
+                               request_id = (unsigned char)response_queue.u.response_id;
+                               if (request_id != 0) {
+                                       /* unexpected request id */
+                                       printk(KERN_WARNING "3w-xxxx: tw_initia
+lize_units(): Unexpected request id.\n");
+                                       return 1;
+                               }
+                               if (command_packet->status != 0) {
+                                       /* bad response */
+                                       printk(KERN_WARNING "3w-xxxx: tw_initia
+lize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+                                       return 1;
+                               }
+                               found = 1;
+                               break;
+                       }
+               }
+               if (found == 0) {
+                       /* response never received */
+                       printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No
+ response.\n");
+                       return 1;
+               }
+
+               param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+               raid_level = (unsigned char *)&(param->data[1]);
+               if (*raid_level == 5) {
+                       dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
+                       tw_dev->is_raid_five[j] = 1;
+                       num_raid_five++;
+               }
+       }
+       tw_dev->num_raid_five = num_raid_five;
+
+       /* Now allocate raid5 bounce buffers */
+       if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+               for (i=0;i<TW_Q_LENGTH;i++) {
+                       tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*256, 2);
+                       if (tw_dev->bounce_buffer[i] == NULL) {
+                               printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bounce buffer allocation failed.\n");
+                               return 1;
+                       }
+                       memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*256);
+               }
+       }
   
        return 0;
 } /* End tw_initialize_units() */
@@ -1288,12 +1421,17 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                case TW_OP_SET_PARAM:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n",
                        ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
-                       command_packet->byte0.opcode = TW_OP_SET_PARAM;
-                       param->table_id = ioctl->table_id;
-                       param->parameter_id = ioctl->parameter_id;
-                       param->parameter_size_bytes = ioctl->parameter_size_bytes;
-                       memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
-                       break;
+                       if (ioctl->data != NULL) {
+                               command_packet->byte0.opcode = TW_OP_SET_PARAM;
+                               param->table_id = ioctl->table_id;
+                               param->parameter_id = ioctl->parameter_id;
+                               param->parameter_size_bytes = ioctl->parameter_size_bytes;
+                               memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
+                               break;
+                       } else {
+                               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+                               return 1;
+                       }
                case TW_OP_AEN_LISTEN:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n");
                        if (tw_dev->aen_head == tw_dev->aen_tail) {
@@ -1318,11 +1456,15 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                        tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
                        return 0;
                case TW_CMD_PACKET:
-                 memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-                 command_packet->request_id = request_id;
-                 tw_post_command_packet(tw_dev, request_id);
-
-                 return 0;
+                       if (ioctl->data != NULL) {
+                               memcpy(command_packet, ioctl->data, sizeof(TW_Command));
+                               command_packet->request_id = request_id;
+                               tw_post_command_packet(tw_dev, request_id);
+                               return 0;
+                       } else {
+                               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+                               return 1;
+                       }
                default:
                        printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
                        tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -1602,10 +1744,8 @@ int tw_scsi_detect(Scsi_Host_Template *tw_host)
                return 0;
        }
 
-       spin_unlock_irq(&io_request_lock);
        ret = tw_findcards(tw_host);
-       spin_lock_irq(&io_request_lock);
-       
+
        return ret;
 } /* End tw_scsi_detect() */
 
@@ -1763,6 +1903,7 @@ int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, int
                tw_copy_info(&info, "Max sector count:              %3d\n", tw_dev->max_sector_count);
                tw_copy_info(&info, "Resets:                        %3d\n", tw_dev->num_resets);
                tw_copy_info(&info, "Aborts:                        %3d\n", tw_dev->num_aborts);
+               tw_copy_info(&info, "AEN's:                         %3d\n", tw_dev->aen_count);
        }
        if (info.position > info.offset) {
                return (info.position - info.offset);
@@ -1780,6 +1921,13 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        int flags = 0;
        TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
 
+       if (tw_dev == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
+               SCpnt->result = (DID_ERROR << 16);
+               done(SCpnt);
+               return 0;
+       }
+
        spin_lock_irqsave(&tw_dev->tw_lock, flags);
        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
 
@@ -1790,20 +1938,6 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
                return 0;
        }
-       if (done == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid done function.\n");
-               SCpnt->result = (DID_ERROR << 16);
-               done(SCpnt);
-               spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
-               return 0;
-       }
-       if (tw_dev == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
-               SCpnt->result = (DID_ERROR << 16);
-               done(SCpnt);
-               spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
-               return 0;
-       }
        
        /* Save done function into Scsi_Cmnd struct */
        SCpnt->scsi_done = done;
@@ -2104,7 +2238,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
        TW_Command *command_packet;
        u32 command_que_addr, command_que_value = 0;
        u32 lba = 0x0, num_sectors = 0x0;
-       int i;
+       int i, count = 0;
        Scsi_Cmnd *srb;
        struct scatterlist *sglist;
 
@@ -2161,23 +2295,45 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
        command_packet->byte8.io.lba = lba;
        command_packet->byte6.block_count = num_sectors;
 
-       /* Do this if there are no sg list entries */
-       if (tw_dev->srb[request_id]->use_sg == 0) {    
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-               command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
-               command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-       }
+       if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
+               /* Do this if there are no sg list entries */
+               if (tw_dev->srb[request_id]->use_sg == 0) {    
+                       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+                       command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
+                       command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+               }
 
-       /* Do this if we have multiple sg list entries */
-       if (tw_dev->srb[request_id]->use_sg > 0) {
-               for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-                       command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
-                       command_packet->byte8.io.sgl[i].length = sglist[i].length;
-                       command_packet->size+=2;
+               /* Do this if we have multiple sg list entries */
+               if (tw_dev->srb[request_id]->use_sg > 0) {
+                       for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+                               command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
+                               command_packet->byte8.io.sgl[i].length = sglist[i].length;
+                               command_packet->size+=2;
+                       }
+                       if (tw_dev->srb[request_id]->use_sg >= 1)
+                               command_packet->size-=2;
                }
-               if (tw_dev->srb[request_id]->use_sg > 1)
-                       command_packet->size-=2;
-       }
+       } else {
+                /* Do this if there are no sg list entries for raid 5 */
+                if (tw_dev->srb[request_id]->use_sg == 0) {
+                       dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
+                       memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
+                       command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+                       command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+                }
+
+                /* Do this if we have multiple sg list entries for raid 5 */
+                if (tw_dev->srb[request_id]->use_sg > 0) {
+                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
+                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
+                               count+=sglist[i].length;
+                        }
+                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+                        command_packet->byte8.io.sgl[0].length = count;
+                        command_packet->size = 5; /* single sgl */
+                }
+        }
 
        /* Update SG statistics */
        tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
@@ -2287,7 +2443,7 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
        /* Poll for completion */
        imax = TW_POLL_MAX_RETRIES;
        for (i=0;i<imax;i++) {
-               mdelay(10);
+               mdelay(5);
                status_reg_value = inl(status_reg_addr);
                if (tw_check_bits(status_reg_value)) {
                        printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
index 0e27a9089289e816cc3f3b9cb9b78eee612c45cf..d3fbfdf699db9eadee6701059ad5e4fe155e5dea 100644 (file)
 #define TW_COMMAND_ALIGNMENT_MASK            0x1ff
 #define TW_INIT_MESSAGE_CREDITS                      0x100
 #define TW_INIT_COMMAND_PACKET_SIZE          0x3
-#define TW_POLL_MAX_RETRIES                  10000
+#define TW_POLL_MAX_RETRIES                  20000
 #define TW_MAX_SGL_LENGTH                    62
-#define TW_Q_LENGTH                          256
+#define TW_Q_LENGTH                          16
 #define TW_Q_START                           0
 #define TW_MAX_SLOT                          32
 #define TW_MAX_PCI_BUSES                     255
@@ -262,8 +262,11 @@ typedef struct TAG_TW_Device_Extension {
        TW_Registers            registers;
        u32                     *alignment_virtual_address[TW_Q_LENGTH];
        u32                     alignment_physical_address[TW_Q_LENGTH];
+       u32                     *bounce_buffer[TW_Q_LENGTH];
        int                     is_unit_present[TW_MAX_UNITS];
+       int                     is_raid_five[TW_MAX_UNITS];
        int                     num_units;
+       int                     num_raid_five;
        u32                     *command_packet_virtual_address[TW_Q_LENGTH];
        u32                     command_packet_physical_address[TW_Q_LENGTH];
        struct pci_dev          *tw_pci_dev;
@@ -286,6 +289,7 @@ typedef struct TAG_TW_Device_Extension {
        u32                     num_resets;
        u32                     sector_count;
        u32                     max_sector_count;
+       u32                     aen_count;
        struct Scsi_Host        *host;
        spinlock_t              tw_lock;
        unsigned char           ioctl_size[TW_Q_LENGTH];
index 8bc5afee96ea20942dced16e0d3e2c2b24918bed..91438fff9eee90a1a07d3ffd1f4273c46d6b4667 100644 (file)
@@ -665,7 +665,7 @@ static void internal_done(Scsi_Cmnd *SCpnt) {
 }
 
 
-static void wait_intr() {
+static void wait_intr(void) {
     int i = jiffies + WATCHDOG;
     
     while(time_after(i,jiffies) && !(inb(STAT_REG)&0xe0)) /* wait for a pseudo-interrupt */
@@ -981,7 +981,7 @@ NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs){
 }
 
 #ifndef IRQ_LEV
-static int irq_probe()
+static int irq_probe(void)
 {
     int irqs, irq;
     int i;
@@ -1013,7 +1013,7 @@ static int irq_probe()
 }
 #endif /* IRQ_LEV */
 
-static void chip_init()
+static void chip_init(void)
 {
     REG1;
 #if USE_DMA
index b7cc1cf12c13455dfced67b95701e32ddcc17592..5e2574a467da293cd06bd6e6758bc10c440a82f5 100644 (file)
@@ -1998,14 +1998,14 @@ static void busfree_run(struct Scsi_Host *shpnt)
                        if (!HOSTDATA(shpnt)->commands)
                                SETPORT(PORTA, 0);      /* turn led off */
 
-                       kfree(DONE_SC->host_scribble);
-                       DONE_SC->host_scribble=0;
-
                        DO_UNLOCK(flags);
                        DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC);
                        DONE_SC->scsi_done(DONE_SC);
                        DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC);
                        DO_LOCK(flags);
+
+                       kfree(DONE_SC->host_scribble);
+                       DONE_SC->host_scribble=0;
                }
 
                DONE_SC=0;
@@ -2872,11 +2872,11 @@ static void rsti_run(struct Scsi_Host *shpnt)
                if (!ptr->device->soft_reset) {
                        remove_SC(&DISCONNECTED_SC, ptr);
 
-                       kfree(ptr->host_scribble);
-                       ptr->host_scribble=0;
-
                        ptr->result =  DID_RESET << 16;
                        ptr->scsi_done(ptr);
+
+                       kfree(ptr->host_scribble);
+                       ptr->host_scribble=0;
                }
 
                ptr = next;
index 543d380a25c82d69d13d5a408664fffbafc6f81d..6f4aabf24377bca64c36d2f3689badc124e40991 100644 (file)
@@ -59,7 +59,7 @@ int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
        struct pci_dev *pdev = NULL;
 
        if (!pci_present()) {
-               dmx3191d_printk("PCI support not enabled\n");
+               printk(KERN_WARNING "dmx3191: PCI support not enabled\n");
                return 0;
        }
 
@@ -75,7 +75,7 @@ int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
                port = pci_resource_start (pdev, 0);
                
                if (!request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME)) {
-                       dmx3191d_printk("region 0x%lx-0x%lx already reserved\n",
+                       printk(KERN_ERR "dmx3191: region 0x%lx-0x%lx already reserved\n",
                                port, port + DMX3191D_REGION);
                        continue;
                }
@@ -93,7 +93,7 @@ int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
 
                if (request_irq(pdev->irq, dmx3191d_do_intr, SA_SHIRQ,
                                DMX3191D_DRIVER_NAME, instance)) {
-                       dmx3191d_printk("irq %d not available\n", pdev->irq);
+                       printk(KERN_WARNING "dmx3191: IRQ %d not available - switching to polled mode.\n", pdev->irq);
                        /* Steam powered scsi controllers run without an IRQ
                           anyway */
                        instance->irq = IRQ_NONE;
index 7a5ad1b69ab83f5df9b75d82ecef1eb677048413..08745d228f1dab188420830541fe2b601c44959d 100644 (file)
@@ -20,8 +20,6 @@
 #define PCI_DEVICE_ID_DOMEX_DMX3191D   0x0001
 #endif
 
-#define dmx3191d_printk( args... )     printk(__FILE__": " ##args)
-
 #ifndef ASM
 int dmx3191d_abort(Scsi_Cmnd *);
 int dmx3191d_detect(Scsi_Host_Template *);
index 3d587edce3f1d16dba0591eeb362eff2e038a6ef..20b9ffef16043a5e873d2f1c5351b361423ecbfb 100644 (file)
@@ -482,6 +482,7 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
         DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
        cmd->result = DID_OK << 16;
        done(cmd);
+       restore_flags(flags);
 
        return(0);
     }
index 7d94928042e9dbbc0b35b1ca88caf3b8dc058062..50e368f13f6b73a548c0c5b6c6d052a9bf2750eb 100644 (file)
@@ -168,6 +168,11 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     retval->loaded_as_module = 1;
     if (flag_new) {
        shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
+        if (!shn) {
+                kfree(retval);
+                printk(KERN_ERR "scsi: out of memory(2) in scsi_register.\n");
+                return NULL;
+        }
        shn->name = kmalloc(hname_len + 1, GFP_ATOMIC);
        if (hname_len > 0)
            strncpy(shn->name, hname, hname_len);
index 9724f2091efdc399243ee772bd731448dcd50da4..2b1730b968fcbedebac7b0a527531530c3845e08 100644 (file)
@@ -1528,6 +1528,7 @@ void qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
     if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags))
     {
         COMTRACE('X')
+        spin_unlock_irqrestore(&io_request_lock, cpu_flags);
         return;
     }
     ha->isr_count++;
index 1e9b3b89be05f131bb21262f4983078731124c2e..01d6679250a954ce98ee59bd837294587eba9726 100644 (file)
@@ -99,6 +99,9 @@ static int proc_scsi_write(struct file * file, const char * buf,
        char * page;
        char *start;
     
+       if (hpnt->hostt->proc_info == NULL)
+               ret = -ENOSYS;
+
        if (count > PROC_BLOCK_SIZE)
                return -EOVERFLOW;
 
@@ -110,11 +113,9 @@ static int proc_scsi_write(struct file * file, const char * buf,
                return -EFAULT;
        }
 
-       if (hpnt->hostt->proc_info == NULL)
-               ret = -ENOSYS;
-       else
-               ret = hpnt->hostt->proc_info(page, &start, 0, count,
-                                               hpnt->host_no, 1);
+       ret = hpnt->hostt->proc_info(page, &start, 0, count,
+                                    hpnt->host_no, 1);
+
        free_page((ulong) page);
        return(ret);
 }
@@ -125,6 +126,10 @@ void build_proc_dir_entries(Scsi_Host_Template * tpnt)
        char name[10];  /* see scsi_unregister_host() */
 
        tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
+        if (!tpnt->proc_dir) {
+                printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries");
+                return;
+        }
        tpnt->proc_dir->owner = tpnt->module;
 
        hpnt = scsi_hostlist;
index d02bee36decdad79bb3cc87eeabc86537af9fe97..03e6a188154b246c0c5f3cdba6e0c7a20fabd778 100644 (file)
@@ -6,6 +6,9 @@
  *  Changes : 
  * 
  *  Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking
+ *  Alan Cox <alan@redhat.com> : Cleaned up code formatting
+ *                              Fixed an irq locking bug
+ *                              Added ISAPnP support
  * 
  *  LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
  *
 #include <asm/io.h>
 #include <linux/blk.h>
 #include <linux/version.h>
+#include <linux/isapnp.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
 #include "sym53c416.h"
 
-#define VERSION_STRING        "Version 1.0.0"
+#define VERSION_STRING        "Version 1.0.0-ac"
 
 #define TC_LOW       0x00     /* Transfer counter low        */
 #define TC_MID       0x01     /* Transfer counter mid        */
@@ -203,24 +207,24 @@ static unsigned int sym53c416_base_3[2] = {0,0};
 #define MAXHOSTS 4
 
 enum phases
-  {
-  idle,
-  data_out,
-  data_in,
-  command_ph,
-  status_ph,
-  message_out,
-  message_in
-  };
+{
+       idle,
+       data_out,
+       data_in,
+       command_ph,
+       status_ph,
+       message_out,
+       message_in
+};
 
 typedef struct
-  {
-  int base;
-  int irq;
-  int scsi_id;
-  } host;
+{
+       int base;
+       int irq;
+       int scsi_id;
+} host;
 
-host hosts[MAXHOSTS] = {
+static host hosts[MAXHOSTS] = {
                        {0, 0, SYM53C416_SCSI_ID},
                        {0, 0, SYM53C416_SCSI_ID},
                        {0, 0, SYM53C416_SCSI_ID},
@@ -228,579 +232,616 @@ host hosts[MAXHOSTS] = {
                        };
 
 static int host_index = 0;
-
 static char info[120];
-
 static Scsi_Cmnd *current_command = NULL;
+static int fastpio = 1;
 
-int fastpio = 1;
-
-int probeaddrs[] = {0x200, 0x220, 0x240, 0};
+static int probeaddrs[] = {0x200, 0x220, 0x240, 0};
 
 static void sym53c416_set_transfer_counter(int base, unsigned int len)
-  {
-  /* Program Transfer Counter */
-  outb(len & 0x0000FF, base + TC_LOW);
-  outb((len & 0x00FF00) >> 8, base + TC_MID);
-  outb((len & 0xFF0000) >> 16, base + TC_HIGH);
-  }
+{
+       /* Program Transfer Counter */
+       outb(len & 0x0000FF, base + TC_LOW);
+       outb((len & 0x00FF00) >> 8, base + TC_MID);
+       outb((len & 0xFF0000) >> 16, base + TC_HIGH);
+}
 
 /* Returns the number of bytes read */
 static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len)
-  {
-  unsigned int orig_len = len;
-  unsigned long flags = 0;
-  unsigned int bytes_left;
-  int i;
-  int timeout = READ_TIMEOUT;
-
-  /* Do transfer */
-  save_flags(flags);
-  cli();
-  while(len && timeout)
-    {
-    bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
-    if(fastpio && bytes_left > 3)
-      {
-      insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
-      buffer += bytes_left & 0xFC;
-      len -= bytes_left & 0xFC;
-      }
-    else if(bytes_left > 0)
-      {
-      len -= bytes_left;
-      for(; bytes_left > 0; bytes_left--)
-        *(buffer++) = inb(base + PIO_FIFO_1);
-      }
-    else
-      {
-      i = jiffies + timeout;
-      restore_flags(flags);
-      while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
-        if(inb(base + PIO_INT_REG) & SCI)
-          timeout = 0;
-      save_flags(flags);
-      cli();
-      if(inb(base + PIO_INT_REG) & EMPTY)
-        timeout = 0;
-      }
-    }
-  restore_flags(flags);
-  return orig_len - len;
-  }
+{
+       unsigned int orig_len = len;
+       unsigned long flags = 0;
+       unsigned int bytes_left;
+       int i;
+       int timeout = READ_TIMEOUT;
+
+       /* Do transfer */
+       save_flags(flags);
+       cli();
+       while(len && timeout)
+       {
+               bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
+               if(fastpio && bytes_left > 3)
+               {
+                       insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
+                       buffer += bytes_left & 0xFC;
+                       len -= bytes_left & 0xFC;
+               }
+               else if(bytes_left > 0)
+               {
+                       len -= bytes_left;
+                       for(; bytes_left > 0; bytes_left--)
+                               *(buffer++) = inb(base + PIO_FIFO_1);
+               }
+               else
+               {
+                       i = jiffies + timeout;
+                       restore_flags(flags);
+                       while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
+                               if(inb(base + PIO_INT_REG) & SCI)
+                                       timeout = 0;
+                       save_flags(flags);
+                       cli();
+                       if(inb(base + PIO_INT_REG) & EMPTY)
+                               timeout = 0;
+               }
+       }
+       restore_flags(flags);
+       return orig_len - len;
+}
 
 /* Returns the number of bytes written */
 static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len)
-  {
-  unsigned int orig_len = len;
-  unsigned long flags = 0;
-  unsigned int bufferfree;
-  unsigned int i;
-  unsigned int timeout = WRITE_TIMEOUT;
-
-  /* Do transfer */
-  save_flags(flags);
-  cli();
-  while(len && timeout)
-    {
-    bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
-    if(bufferfree > len)
-      bufferfree = len;
-    if(fastpio && bufferfree > 3)
-      {
-      outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
-      buffer += bufferfree & 0xFC;
-      len -= bufferfree & 0xFC;
-      }
-    else if(bufferfree > 0)
-      {
-      len -= bufferfree;
-      for(; bufferfree > 0; bufferfree--)
-        outb(*(buffer++), base + PIO_FIFO_1);
-      }
-    else
-      {
-      i = jiffies + timeout;
-      restore_flags(flags);
-      while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
-        ;
-      save_flags(flags);
-      cli();
-      if(inb(base + PIO_INT_REG) & FULL)
-        timeout = 0;
-      }
-    }
-  restore_flags(flags);
-  return orig_len - len;
-  }
+{
+       unsigned int orig_len = len;
+       unsigned long flags = 0;
+       unsigned int bufferfree;
+       unsigned int i;
+       unsigned int timeout = WRITE_TIMEOUT;
+
+       /* Do transfer */
+       save_flags(flags);
+       cli();
+       while(len && timeout)
+       {
+               bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
+               if(bufferfree > len)
+                       bufferfree = len;
+               if(fastpio && bufferfree > 3)
+               {
+                       outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
+                       buffer += bufferfree & 0xFC;
+                       len -= bufferfree & 0xFC;
+               }
+               else if(bufferfree > 0)
+               {
+                       len -= bufferfree;
+                       for(; bufferfree > 0; bufferfree--)
+                               outb(*(buffer++), base + PIO_FIFO_1);
+               }
+               else
+               {
+                       i = jiffies + timeout;
+                       restore_flags(flags);
+                       while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
+                               ;
+                       save_flags(flags);
+                       cli();
+                       if(inb(base + PIO_INT_REG) & FULL)
+                               timeout = 0;
+               }
+       }
+       restore_flags(flags);
+       return orig_len - len;
+}
 
 static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
-  {
-  int base = 0;
-  int i;
-  unsigned long flags = 0;
-  unsigned char status_reg, pio_int_reg, int_reg;
-  struct scatterlist *sglist;
-  unsigned int sgcount;
-  unsigned int tot_trans = 0;
-
-  /* We search the base address of the host adapter which caused the interrupt */
-  for(i = 0; i < host_index && !base; i++)
-    if(irq == hosts[i].irq)
-      base = hosts[i].base;
-  /* If no adapter found, we cannot handle the interrupt. Leave a message */
-  /* and continue. This should never happen...                            */
-  if(!base)
-    {
-    printk("sym53c416: No host adapter defined for interrupt %d\n", irq);
-    return;
-    }
-  /* Now we have the base address and we can start handling the interrupt */
-  save_flags(flags);
-  cli();
-  status_reg = inb(base + STATUS_REG);
-  pio_int_reg = inb(base + PIO_INT_REG);
-  int_reg = inb(base + INT_REG);
-  restore_flags(flags);
-
-  /* First, we handle error conditions */
-  if(int_reg & SCI)         /* SCSI Reset */
-    {
-    printk("sym53c416: Warning: Reset received\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_RESET << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(int_reg & ILCMD)       /* Illegal Command */
-    {
-    printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG));
-    current_command->SCp.phase = idle;
-    current_command->result = DID_ERROR << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(status_reg & GE)         /* Gross Error */
-    {
-    printk("sym53c416: Warning: Gross Error\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_ERROR << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(status_reg & PE)         /* Parity Error */
-    {
-    printk("sym53c416: Warning: Parity Error\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_PARITY << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(pio_int_reg & (CE | OUE))
-    {
-    printk("sym53c416: Warning: PIO Interrupt Error\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_ERROR << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(int_reg & DIS)           /* Disconnect */
-    {
-    if(current_command->SCp.phase != message_in)
-      current_command->result = DID_NO_CONNECT << 16;
-    else
-      current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
-    current_command->SCp.phase = idle;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  /* Now we handle SCSI phases         */
-  switch(status_reg & PHBITS)       /* Filter SCSI phase out of status reg */
-    {
-    case PHASE_DATA_OUT:
-      {
-      if(int_reg & BS)
-        {
-        current_command->SCp.phase = data_out;
-        outb(FLUSH_FIFO, base + COMMAND_REG);
-        sym53c416_set_transfer_counter(base, current_command->request_bufflen);
-        outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
-        if(!current_command->use_sg)
-          tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
-        else
-          {
-          sgcount = current_command->use_sg;
-          sglist = current_command->request_buffer;
-          while(sgcount--)
-            {
-            tot_trans += sym53c416_write(base, sglist->address, sglist->length);
-            sglist++;
-            }
-          }
-        if(tot_trans < current_command->underflow)
-          printk("sym53c416: Warning: underflow, wrote %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
-        }
-      break;
-      }
-    case PHASE_DATA_IN:
-      {
-      if(int_reg & BS)
-        {
-        current_command->SCp.phase = data_in;
-        outb(FLUSH_FIFO, base + COMMAND_REG);
-        sym53c416_set_transfer_counter(base, current_command->request_bufflen);
-        outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
-        if(!current_command->use_sg)
-          tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
-        else
-          {
-          sgcount = current_command->use_sg;
-          sglist = current_command->request_buffer;
-          while(sgcount--)
-            {
-            tot_trans += sym53c416_read(base, sglist->address, sglist->length);
-            sglist++;
-            }
-          }
-        if(tot_trans < current_command->underflow)
-          printk("sym53c416: Warning: underflow, read %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
-        }
-      break;
-      }
-    case PHASE_COMMAND:
-      {
-      current_command->SCp.phase = command_ph;
-      printk("sym53c416: Warning: Unknown interrupt in command phase\n");
-      break;
-      }
-    case PHASE_STATUS:
-      {
-      current_command->SCp.phase = status_ph;
-      outb(FLUSH_FIFO, base + COMMAND_REG);
-      outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
-      break;
-      }
-    case PHASE_RESERVED_1:
-    case PHASE_RESERVED_2:
-      {
-      printk("sym53c416: Warning: Reserved phase\n");
-      break;
-      }
-    case PHASE_MESSAGE_OUT:
-      {
-      current_command->SCp.phase = message_out;
-      outb(SET_ATN, base + COMMAND_REG);
-      outb(MSG_ACCEPTED, base + COMMAND_REG);
-      break;
-      }
-    case PHASE_MESSAGE_IN:
-      {
-      current_command->SCp.phase = message_in;
-      current_command->SCp.Status = inb(base + SCSI_FIFO);
-      current_command->SCp.Message = inb(base + SCSI_FIFO);
-      if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
-        outb(SET_ATN, base + COMMAND_REG);
-      outb(MSG_ACCEPTED, base + COMMAND_REG);
-      break;
-      }
-    }
-  }
+{
+       int base = 0;
+       int i;
+       unsigned long flags = 0;
+       unsigned char status_reg, pio_int_reg, int_reg;
+       struct scatterlist *sglist;
+       unsigned int sgcount;
+       unsigned int tot_trans = 0;
+
+       /* We search the base address of the host adapter which caused the interrupt */
+       /* FIXME: should pass dev_id sensibly as hosts[i] */
+       for(i = 0; i < host_index && !base; i++)
+               if(irq == hosts[i].irq)
+                       base = hosts[i].base;
+       /* If no adapter found, we cannot handle the interrupt. Leave a message */
+       /* and continue. This should never happen...                            */
+       if(!base)
+       {
+               printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
+               return;
+       }
+       /* Now we have the base address and we can start handling the interrupt */
+
+       spin_lock_irqsave(&io_request_lock,flags);
+       status_reg = inb(base + STATUS_REG);
+       pio_int_reg = inb(base + PIO_INT_REG);
+       int_reg = inb(base + INT_REG);
+       spin_unlock_irqrestore(&io_request_lock, flags);
+
+       /* First, we handle error conditions */
+       if(int_reg & SCI)         /* SCSI Reset */
+       {
+               printk(KERN_DEBUG "sym53c416: Reset received\n");
+               current_command->SCp.phase = idle;
+               current_command->result = DID_RESET << 16;
+               spin_lock_irqsave(&io_request_lock, flags);
+               current_command->scsi_done(current_command);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       if(int_reg & ILCMD)       /* Illegal Command */
+       {
+               printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG));
+               current_command->SCp.phase = idle;
+               current_command->result = DID_ERROR << 16;
+               spin_lock_irqsave(&io_request_lock, flags);
+               current_command->scsi_done(current_command);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       if(status_reg & GE)         /* Gross Error */
+       {
+               printk(KERN_WARNING "sym53c416: Controller reports gross error.\n");
+               current_command->SCp.phase = idle;
+               current_command->result = DID_ERROR << 16;
+               spin_lock_irqsave(&io_request_lock, flags);
+               current_command->scsi_done(current_command);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       if(status_reg & PE)         /* Parity Error */
+       {
+               printk(KERN_WARNING "sym53c416:SCSI parity error.\n");
+               current_command->SCp.phase = idle;
+               current_command->result = DID_PARITY << 16;
+               spin_lock_irqsave(&io_request_lock, flags);
+               current_command->scsi_done(current_command);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       if(pio_int_reg & (CE | OUE))
+       {
+               printk(KERN_WARNING "sym53c416: PIO interrupt error.\n");
+               current_command->SCp.phase = idle;
+               current_command->result = DID_ERROR << 16;
+               spin_lock_irqsave(&io_request_lock, flags);
+               current_command->scsi_done(current_command);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       if(int_reg & DIS)           /* Disconnect */
+       {
+               if(current_command->SCp.phase != message_in)
+                       current_command->result = DID_NO_CONNECT << 16;
+               else
+                       current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
+               current_command->SCp.phase = idle;
+               spin_lock_irqsave(&io_request_lock, flags);
+               current_command->scsi_done(current_command);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+               return;
+       }
+       /* Now we handle SCSI phases         */
+
+       switch(status_reg & PHBITS)       /* Filter SCSI phase out of status reg */
+       {
+               case PHASE_DATA_OUT:
+               {
+                       if(int_reg & BS)
+                       {
+                               current_command->SCp.phase = data_out;
+                               outb(FLUSH_FIFO, base + COMMAND_REG);
+                               sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+                               outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+                               if(!current_command->use_sg)
+                                       tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
+                               else
+                               {
+                                       sgcount = current_command->use_sg;
+                                       sglist = current_command->request_buffer;
+                                       while(sgcount--)
+                                       {
+                                               tot_trans += sym53c416_write(base, sglist->address, sglist->length);
+                                               sglist++;
+                                       }
+                               }
+                               if(tot_trans < current_command->underflow)
+                                       printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+                       }
+                       break;
+               }
+
+               case PHASE_DATA_IN:
+               {
+                       if(int_reg & BS)
+                       {
+                               current_command->SCp.phase = data_in;
+                               outb(FLUSH_FIFO, base + COMMAND_REG);
+                               sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+                               outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+                               if(!current_command->use_sg)
+                                       tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
+                               else
+                               {
+                                       sgcount = current_command->use_sg;
+                                       sglist = current_command->request_buffer;
+                                       while(sgcount--)
+                                       {
+                                               tot_trans += sym53c416_read(base, sglist->address, sglist->length);
+                                               sglist++;
+                                       }
+                               }
+                               if(tot_trans < current_command->underflow)
+                                       printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+                       }
+                       break;
+               }
+
+               case PHASE_COMMAND:
+               {
+                       current_command->SCp.phase = command_ph;
+                       printk(KERN_ERR "sym53c416: Unknown interrupt in command phase.\n");
+                       break;
+               }
+
+               case PHASE_STATUS:
+               {
+                       current_command->SCp.phase = status_ph;
+                       outb(FLUSH_FIFO, base + COMMAND_REG);
+                       outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
+                       break;
+               }
+               
+               case PHASE_RESERVED_1:
+               case PHASE_RESERVED_2:
+               {
+                       printk(KERN_ERR "sym53c416: Reserved phase occurred.\n");
+                       break;
+               }
+
+               case PHASE_MESSAGE_OUT:
+               {
+                       current_command->SCp.phase = message_out;
+                       outb(SET_ATN, base + COMMAND_REG);
+                       outb(MSG_ACCEPTED, base + COMMAND_REG);
+                       break;
+               }
+
+               case PHASE_MESSAGE_IN:
+               {
+                       current_command->SCp.phase = message_in;
+                       current_command->SCp.Status = inb(base + SCSI_FIFO);
+                       current_command->SCp.Message = inb(base + SCSI_FIFO);
+                       if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
+                               outb(SET_ATN, base + COMMAND_REG);
+                       outb(MSG_ACCEPTED, base + COMMAND_REG);
+                       break;
+               }
+       }
+}
 
 static void sym53c416_init(int base, int scsi_id)
-  {
-  outb(RESET_CHIP, base + COMMAND_REG);
-  outb(NOOP, base + COMMAND_REG);
-  outb(0x99, base + TOM); /* Time out of 250 ms */
-  outb(0x05, base + STP);
-  outb(0x00, base + SYNC_OFFSET);
-  outb(EPC | scsi_id, base + CONF_REG_1);
-  outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
-  outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
-  outb(0x83 | EAN, base + CONF_REG_4);
-  outb(IE | WSE0, base + CONF_REG_5);
-  outb(0, base + FEATURE_EN);
-  }
+{
+       outb(RESET_CHIP, base + COMMAND_REG);
+       outb(NOOP, base + COMMAND_REG);
+       outb(0x99, base + TOM); /* Time out of 250 ms */
+       outb(0x05, base + STP);
+       outb(0x00, base + SYNC_OFFSET);
+       outb(EPC | scsi_id, base + CONF_REG_1);
+       outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
+       outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
+       outb(0x83 | EAN, base + CONF_REG_4);
+       outb(IE | WSE0, base + CONF_REG_5);
+       outb(0, base + FEATURE_EN);
+}
 
 static int sym53c416_probeirq(int base, int scsi_id)
-  {
-  int irq, irqs, i;
-
-  /* Clear interrupt register */
-  inb(base + INT_REG);
-  /* Start probing for irq's */
-  irqs = probe_irq_on();
-  /* Reinit chip */
-  sym53c416_init(base, scsi_id);
-  /* Cause interrupt */
-  outb(NOOP, base + COMMAND_REG);
-  outb(ILLEGAL, base + COMMAND_REG);
-  outb(0x07, base + DEST_BUS_ID);
-  outb(0x00, base + DEST_BUS_ID);
-  /* Wait for interrupt to occur */
-  i = jiffies + 20;
-  while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
-    barrier();
-  if(i <= jiffies) /* timed out */
-    return 0;
-  /* Get occurred irq */
-  irq = probe_irq_off(irqs);
-  sym53c416_init(base, scsi_id);
-  return irq;
-  }
+{
+       int irq, irqs, i;
+
+       /* Clear interrupt register */
+       inb(base + INT_REG);
+       /* Start probing for irq's */
+       irqs = probe_irq_on();
+       /* Reinit chip */
+       sym53c416_init(base, scsi_id);
+       /* Cause interrupt */
+       outb(NOOP, base + COMMAND_REG);
+       outb(ILLEGAL, base + COMMAND_REG);
+       outb(0x07, base + DEST_BUS_ID);
+       outb(0x00, base + DEST_BUS_ID);
+       /* Wait for interrupt to occur */
+       i = jiffies + 20;
+       while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
+               barrier();
+       if(i <= jiffies) /* timed out */
+               return 0;
+       /* Get occurred irq */
+       irq = probe_irq_off(irqs);
+       sym53c416_init(base, scsi_id);
+       return irq;
+}
 
 /* Setup: sym53c416=base,irq */
 void sym53c416_setup(char *str, int *ints)
-  {
-  int i;
-
-  if(host_index >= MAXHOSTS)
-    {
-    printk("sym53c416.c: Too many hosts defined\n");
-    }
-  else
-    {
-    if(ints[0] < 1 || ints[0] > 2)
-      {
-      printk("sym53c416.c: Wrong number of parameters:\n");
-      printk("sym53c416.c: usage: sym53c416=<base>[,<irq>]\n");
-      }
-    else
-      {
-      for(i = 0; i < host_index && i >= 0; i++)
-        if(hosts[i].base == ints[1])
-          i = -2;
-      if(i >= 0)
-        {
-        hosts[host_index].base = ints[1];
-        hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
-        host_index++;
-        }
-      }
-    }
-  }
+{
+       int i;
+
+       if(host_index >= MAXHOSTS)
+       {
+               printk(KERN_WARNING "sym53c416: Too many hosts defined\n");
+               return;
+       }
+       if(ints[0] < 1 || ints[0] > 2)
+       {
+               printk(KERN_ERR "sym53c416: Wrong number of parameters:\n");
+               printk(KERN_ERR "sym53c416: usage: sym53c416=<base>[,<irq>]\n");
+               return;
+       }
+       for(i = 0; i < host_index && i >= 0; i++)
+               if(hosts[i].base == ints[1])
+                       i = -2;
+       if(i >= 0)
+       {
+               hosts[host_index].base = ints[1];
+               hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
+               host_index++;
+       }
+}
 
 static int sym53c416_test(int base)
-  {
-  outb(RESET_CHIP, base + COMMAND_REG);
-  outb(NOOP, base + COMMAND_REG);
-  if(inb(base + COMMAND_REG) != NOOP)
-    return 0;
-  if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
-    return 0;
-  if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
-    return 0;
-  return 1;
-  }
+{
+       outb(RESET_CHIP, base + COMMAND_REG);
+       outb(NOOP, base + COMMAND_REG);
+       if(inb(base + COMMAND_REG) != NOOP)
+               return 0;
+       if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
+               return 0;
+       if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
+               return 0;
+       return 1;
+}
+
+
+static struct isapnp_device_id id_table[] = {
+       {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+               ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 },
+       {0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
 
 void sym53c416_probe(void)
-  {
-  int *base = probeaddrs;
-  int ints[2];
-
-  ints[0] = 1;
-  for(; *base; base++)
-    if(!check_region(*base, IO_RANGE) && sym53c416_test(*base))
-      {
-      ints[1] = *base;
-      sym53c416_setup(NULL, ints);
-      }
-  }
+{
+       int *base = probeaddrs;
+       int ints[2];
+
+       ints[0] = 1;
+       for(; *base; base++)
+       {
+               if(!check_region(*base, IO_RANGE) && sym53c416_test(*base))
+               {
+                       ints[1] = *base;
+                       sym53c416_setup(NULL, ints);
+               }
+       }
+}
 
 int sym53c416_detect(Scsi_Host_Template *tpnt)
-  {
-  unsigned long flags;
-  struct Scsi_Host * shpnt = NULL;
-  int i;
-  int count;
-
+{
+       unsigned long flags;
+       struct Scsi_Host * shpnt = NULL;
+       int i;
+       int count;
+       struct pci_dev *idev = NULL;
+       
 #ifdef MODULE
-  int ints[3];
-
-  ints[0] = 2;
-  if(sym53c416_base)
-    {
-    ints[1] = sym53c416_base[0];
-    ints[2] = sym53c416_base[1];
-    sym53c416_setup(NULL, ints);
-    }
-  if(sym53c416_base_1)
-    {
-    ints[1] = sym53c416_base_1[0];
-    ints[2] = sym53c416_base_1[1];
-    sym53c416_setup(NULL, ints);
-    }
-  if(sym53c416_base_2)
-    {
-    ints[1] = sym53c416_base_2[0];
-    ints[2] = sym53c416_base_2[1];
-    sym53c416_setup(NULL, ints);
-    }
-  if(sym53c416_base_3)
-    {
-    ints[1] = sym53c416_base_3[0];
-    ints[2] = sym53c416_base_3[1];
-    sym53c416_setup(NULL, ints);
-    }
+       int ints[3];
+
+       ints[0] = 2;
+       if(sym53c416_base)
+       {
+               ints[1] = sym53c416_base[0];
+               ints[2] = sym53c416_base[1];
+               sym53c416_setup(NULL, ints);
+       }
+       if(sym53c416_base_1)
+       {
+               ints[1] = sym53c416_base_1[0];
+               ints[2] = sym53c416_base_1[1];
+               sym53c416_setup(NULL, ints);
+       }
+       if(sym53c416_base_2)
+       {
+               ints[1] = sym53c416_base_2[0];
+               ints[2] = sym53c416_base_2[1];
+               sym53c416_setup(NULL, ints);
+       }
+       if(sym53c416_base_3)
+       {
+               ints[1] = sym53c416_base_3[0];
+               ints[2] = sym53c416_base_3[1];
+               sym53c416_setup(NULL, ints);
+       }
 #endif
-
-  printk("sym53c416.c: %s\n", VERSION_STRING);
-
-  sym53c416_probe();
-
-  /* Now we register and set up each host adapter found... */
-  for(count = 0, i = 0; i < host_index; i++)
-    if(!sym53c416_test(hosts[i].base))
-      printk("No sym53c416 found at address 0x%03x\n", hosts[i].base);
-    else
-      {
-      if(hosts[i].irq == 0)
-        /* We don't have an irq yet, so we should probe for one */
-        if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0)
-          printk("irq autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base);
-      if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))
-        {
-        shpnt = scsi_register(tpnt, 0);
-        if(shpnt==NULL)
-               continue;
-        save_flags(flags);
-        cli();
-        /* Request for specified IRQ */
-        if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
-          {
-          restore_flags(flags);
-          printk("Unable to assign IRQ %d\n", hosts[i].irq);
-          scsi_unregister(shpnt);
-          }
-        else
-          {
-          /* Inform the kernel of our IO range */
-          request_region(hosts[i].base, IO_RANGE, ID);
-          shpnt->unique_id = hosts[i].base;
-          shpnt->io_port = hosts[i].base;
-          shpnt->n_io_port = IO_RANGE;
-          shpnt->irq = hosts[i].irq;
-          shpnt->this_id = hosts[i].scsi_id;
-          sym53c416_init(hosts[i].base, hosts[i].scsi_id);
-          count++;
-          restore_flags(flags);
-          }
-        }
-      }
-  return count;
-  }
+       printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING);
+
+       while((idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('S','L','I'), 
+                               ISAPNP_FUNCTION(0x4163), idev))!=NULL)
+       {
+               int i[3];
+               
+               if(idev->prepare(idev)<0)
+               {
+                       printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n");
+                       continue;
+               }
+               if(idev->activate(idev)<0)
+               {
+                       printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n");
+                       continue;
+               }
+               
+               i[0] = 2;
+               i[1] = idev->resource[0].start;
+               i[2] = idev->irq_resource[0].start;
+               
+               printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n",
+                       i[1], i[2]);
+               sym53c416_setup(NULL, i);
+       }
+       sym53c416_probe();
+
+       /* Now we register and set up each host adapter found... */
+       for(count = 0, i = 0; i < host_index; i++)
+       {
+               if(!sym53c416_test(hosts[i].base))
+                       printk(KERN_WARNING "No sym53c416 found at address 0x%03x\n", hosts[i].base);
+               else
+               {
+                       if(hosts[i].irq == 0)
+                       /* We don't have an irq yet, so we should probe for one */
+                               if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0)
+                                       printk(KERN_WARNING "IRQ autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base);
+                       if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))
+                       {
+                               shpnt = scsi_register(tpnt, 0);
+                               if(shpnt==NULL)
+                                       continue;
+                               save_flags(flags);
+                               cli();
+                               /* FIXME: Request_irq with CLI is not safe */
+                               /* Request for specified IRQ */
+                               if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
+                               {
+                                       restore_flags(flags);
+                                       printk(KERN_ERR "sym53c416: Unable to assign IRQ %d\n", hosts[i].irq);
+                                       scsi_unregister(shpnt);
+                               }
+                               else
+                               {
+                                       /* Inform the kernel of our IO range */
+                                       request_region(hosts[i].base, IO_RANGE, ID);
+                                       shpnt->unique_id = hosts[i].base;
+                                       shpnt->io_port = hosts[i].base;
+                                       shpnt->n_io_port = IO_RANGE;
+                                       shpnt->irq = hosts[i].irq;
+                                       shpnt->this_id = hosts[i].scsi_id;
+                                       sym53c416_init(hosts[i].base, hosts[i].scsi_id);
+                                       count++;
+                                       restore_flags(flags);
+                               }
+                       }
+               }
+       }
+       return count;
+}
 
 const char *sym53c416_info(struct Scsi_Host *SChost)
-  {
-  int i;
-  int base = SChost->io_port;
-  int irq = SChost->irq;
-  int scsi_id = 0;
-  int rev = inb(base + TC_HIGH);
-
-  for(i = 0; i < host_index; i++)
-    if(hosts[i].base == base)
-      scsi_id = hosts[i].scsi_id;
-  sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
-  return info;
-  }
+{
+       int i;
+       int base = SChost->io_port;
+       int irq = SChost->irq;
+       int scsi_id = 0;
+       int rev = inb(base + TC_HIGH);
+
+       for(i = 0; i < host_index; i++)
+               if(hosts[i].base == base)
+                       scsi_id = hosts[i].scsi_id;
+       sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
+       return info;
+}
 
 int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-  {
-  int base;
-  unsigned long flags = 0;
-  int i;
-
-  /* Store base register as we can have more than one controller in the system */
-  base = SCpnt->host->io_port;
-  current_command = SCpnt;                  /* set current command                */
-  current_command->scsi_done = done;        /* set ptr to done function           */
-  current_command->SCp.phase = command_ph;  /* currect phase is the command phase */
-  current_command->SCp.Status = 0;
-  current_command->SCp.Message = 0;
-
-  save_flags(flags);
-  cli();
-  outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target        */
-  outb(FLUSH_FIFO, base + COMMAND_REG);    /* Flush SCSI and PIO FIFO's */
-  /* Write SCSI command into the SCSI fifo */
-  for(i = 0; i < SCpnt->cmd_len; i++)
-    outb(SCpnt->cmnd[i], base + SCSI_FIFO);
-  /* Start selection sequence */
-  outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
-  /* Now an interrupt will be generated which we will catch in out interrupt routine */
-  restore_flags(flags);
-  return 0;
-  }
+{
+       int base;
+       unsigned long flags = 0;
+       int i;
+
+       /* Store base register as we can have more than one controller in the system */
+       base = SCpnt->host->io_port;
+       current_command = SCpnt;                  /* set current command                */
+       current_command->scsi_done = done;        /* set ptr to done function           */
+       current_command->SCp.phase = command_ph;  /* currect phase is the command phase */
+       current_command->SCp.Status = 0;
+       current_command->SCp.Message = 0;
+
+       save_flags(flags);
+       cli();
+       outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target        */
+       outb(FLUSH_FIFO, base + COMMAND_REG);    /* Flush SCSI and PIO FIFO's */
+       /* Write SCSI command into the SCSI fifo */
+       for(i = 0; i < SCpnt->cmd_len; i++)
+               outb(SCpnt->cmnd[i], base + SCSI_FIFO);
+       /* Start selection sequence */
+       outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
+       /* Now an interrupt will be generated which we will catch in out interrupt routine */
+       restore_flags(flags);
+       return 0;
+}
 
 static void internal_done(Scsi_Cmnd *SCpnt)
-  {
-  SCpnt->SCp.Status++;
-  }
-
-int sym53c416_command(Scsi_Cmnd *SCpnt)
-  {
-  sym53c416_queuecommand(SCpnt, internal_done);
-  SCpnt->SCp.Status = 0;
-  while(!SCpnt->SCp.Status)
-    barrier();
-  return SCpnt->result;
-  }
-
-int sym53c416_abort(Scsi_Cmnd *SCpnt)
-  {
-  printk("sym53c416_abort\n");
-
-  /* We don't know how to abort for the moment */
-  return SCSI_ABORT_SNOOZE;
-  }
-
-int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
-  {
-  int base;
-  int scsi_id = -1;
-  int i;
-
-  printk("sym53c416_reset\n");
-  base = SCpnt->host->io_port;
-  /* search scsi_id */
-  for(i = 0; i < host_index && scsi_id != -1; i++)
-    if(hosts[i].base == base)
-      scsi_id = hosts[i].scsi_id;
-  outb(RESET_CHIP, base + COMMAND_REG);
-  outb(NOOP | PIO_MODE, base + COMMAND_REG);
-  outb(RESET_SCSI_BUS, base + COMMAND_REG);
-  sym53c416_init(base, scsi_id);
-  return SCSI_RESET_PENDING;
-  }
-
-int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
-  {
-  int size;
-
-  size = disk->capacity;
-  ip[0] = 64;                         /* heads                        */
-  ip[1] = 32;                         /* sectors                      */
-  if((ip[2] = size >> 11) > 1024)     /* cylinders, test for big disk */
-    {
-    ip[0] = 255;                      /* heads                        */
-    ip[1] = 63;                       /* sectors                      */
-    ip[2] = size / (255 * 63);        /* cylinders                    */
-    }
-  return 0;
-  }
+{
+       SCpnt->SCp.Status++;
+}
+
+static int sym53c416_command(Scsi_Cmnd *SCpnt)
+{
+       sym53c416_queuecommand(SCpnt, internal_done);
+       SCpnt->SCp.Status = 0;
+       while(!SCpnt->SCp.Status)
+               barrier();
+       return SCpnt->result;
+}
+
+static int sym53c416_abort(Scsi_Cmnd *SCpnt)
+{
+       //printk("sym53c416_abort\n");
+       /* We don't know how to abort for the moment */
+       return SCSI_ABORT_SNOOZE;
+}
+
+static int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+       int base;
+       int scsi_id = -1;       
+       int i;
+
+       //printk("sym53c416_reset\n");
+       base = SCpnt->host->io_port;
+       /* search scsi_id */
+       for(i = 0; i < host_index && scsi_id != -1; i++)
+               if(hosts[i].base == base)
+                       scsi_id = hosts[i].scsi_id;
+       outb(RESET_CHIP, base + COMMAND_REG);
+       outb(NOOP | PIO_MODE, base + COMMAND_REG);
+       outb(RESET_SCSI_BUS, base + COMMAND_REG);
+       sym53c416_init(base, scsi_id);
+       return SCSI_RESET_PENDING;
+}
+
+static int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
+{
+       int size;
+
+       size = disk->capacity;
+       ip[0] = 64;                             /* heads                        */
+       ip[1] = 32;                             /* sectors                      */
+       if((ip[2] = size >> 11) > 1024)         /* cylinders, test for big disk */
+       {
+               ip[0] = 255;                    /* heads                        */
+               ip[1] = 63;                     /* sectors                      */
+               ip[2] = size / (255 * 63);      /* cylinders                    */
+       }
+       return 0;
+}
 
 /* Loadable module support */
 #ifdef MODULE
index 5e01bc1186f0a1e852700367f163aace73b5e8f5..8124b1c78d28666c5a2ee37a25951d88c25c3c1c 100644 (file)
 
 #define SYM53C416_SCSI_ID 7
 
-extern int sym53c416_detect(Scsi_Host_Template *);
-extern const char *sym53c416_info(struct Scsi_Host *);
-extern int sym53c416_command(Scsi_Cmnd *);
-extern int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int sym53c416_abort(Scsi_Cmnd *);
-extern int sym53c416_reset(Scsi_Cmnd *, unsigned int);
-extern int sym53c416_bios_param(Disk *, kdev_t, int *);
-extern void sym53c416_setup(char *str, int *ints);
+static int sym53c416_detect(Scsi_Host_Template *);
+static const char *sym53c416_info(struct Scsi_Host *);
+static int sym53c416_command(Scsi_Cmnd *);
+static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_abort(Scsi_Cmnd *);
+static int sym53c416_reset(Scsi_Cmnd *, unsigned int);
+static int sym53c416_bios_param(Disk *, kdev_t, int *);
+static void sym53c416_setup(char *str, int *ints);
 
 #define SYM53C416 {                                          \
                   proc_name:         "sym53c416",   \
index e962e22baab85e1127f7e98a2f299f91847c367c..04122f77f7097719baadc45d882a26f8c7ed0f2a 100644 (file)
@@ -1,12 +1,16 @@
 /*****************************************************************************/
-
 /*
  *      cmpci.c  --  C-Media PCI audio driver.
  *
- *      Copyright (C) 1999  ChenLi Tien (cltien@home.com)
+ *      Copyright (C) 1999  ChenLi Tien (cltien@cmedia.com.tw)
+ *                         C-media support (support@cmedia.com.tw)
  *
- *     Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
+ *     For update, visit:
+ *             http://members.home.net/puresoft/cmedia.html
+ *             http://www.cmedia.com.tw
+ *     
  *      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
@@ -57,8 +61,6 @@
  *                     reported by Johan Maes <joma@telindus.be>
  *    22.03.99   0.12  return EAGAIN instead of EBUSY when O_NONBLOCK
  *                     read/write cannot be executed
- *    20 09 99   0.13  merged the generic changes in sonicvibes since this
- *                    diverged.
  *    18.08.99   1.5   Only deallocate DMA buffer when unloading.
  *    02.09.99   1.6   Enable SPDIF LOOP
  *                     Change the mixer read back
  *                     Add support for modem, S/PDIF loop and 4 channels.
  *                     (8738 only)
  *                     Fix bug cause x11amp cannot play.
- *    $Log: cmpci.c,v $
- *    Revision 2.41  1999/10/27 02:00:05  cltien
- *    Now the fragsize for modem is activated by parameter.
- *
- *    Revision 2.40  1999/10/26 23:38:26  cltien
- *    Remove debugging message in cm_write which may cause module counter not 0.
- *
- *    Revision 2.39  1999/10/26 21:52:50  cltien
- *    I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO.
- *    Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer.
- *
- *    Revision 2.38  1999/10/08 21:59:03  cltien
- *    Set FLINKON and reset FLINKOFF for modem.
  *
- *    Revision 2.37  1999/09/28 02:57:04  cltien
- *    Add set_bus_master() to make sure bus master enabled.
- *
- *    Revision 2.36  1999/09/22 14:15:03  cltien
- *    Use open_sem to avoid multiple access to open_mode.
- *    Use wakeup in IntrClose to activate process in waiting queue.
- *
- *    Revision 2.35  1999/09/22 13:20:53  cltien
- *    Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely.
- *
- *    Revision 2.34  1999/09/22 03:29:57  cltien
- *    Use module count to decide which one to access the dac.
+ *    Fixes:
+ *    Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *    18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
+ *                was calling prog_dmabuf with s->lock held, call missing
+ *                unlock_kernel in cm_midi_release
  *
+ *    Fri May 25 2001 - Carlos Eduardo Gorges <carlos@techlinux.com.br>
+ *    - some driver cleanups
+ *    - spin[un]lock* revision ( fix SMP support )
+ *    - cosmetic code changes
  *
  */
+
 /*****************************************************************************/
       
-#include <linux/config.h>
+#define EXPORT_SYMTAB
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/sound.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
 #include <linux/wrapper.h>
 #ifndef PCI_DEVICE_ID_CMEDIA_CM8738
 #define PCI_DEVICE_ID_CMEDIA_CM8738  0x0111
 #endif
+#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B
+#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
+#endif
 
 #define CM_MAGIC  ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
 
 #define CM_CFMT_STEREO     0x01
 #define CM_CFMT_16BIT      0x02
 #define CM_CFMT_MASK       0x03
-#define CM_CFMT_DACSHIFT   0   
-#define CM_CFMT_ADCSHIFT   2
+#define CM_CFMT_DACSHIFT   2
+#define CM_CFMT_ADCSHIFT   0
 
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
-#define CM_CENABLE_RE      0x2
-#define CM_CENABLE_PE      0x1
+#define CM_ENABLE_CH1      0x2
+#define CM_ENABLE_CH0      0x1
 
 
 /* MIDI buffer sizes */
@@ -238,6 +228,8 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
 #define FMODE_DMFM 0x10
 
+#define SND_DEV_DSP16   5 
+
 /* --------------------------------------------------------------------- */
 
 struct cm_state {
@@ -255,6 +247,7 @@ struct cm_state {
 
        /* hardware resources */
        unsigned int iosb, iobase, iosynth, iomidi, iogame, irq;
+       unsigned short deviceid;
 
         /* mixer stuff */
         struct {
@@ -275,6 +268,7 @@ struct cm_state {
 
        struct dmabuf {
                void *rawbuf;
+               unsigned rawphys;
                unsigned buforder;
                unsigned numfrag;
                unsigned fragshift;
@@ -307,12 +301,48 @@ struct cm_state {
                unsigned char ibuf[MIDIINBUF];
                unsigned char obuf[MIDIOUTBUF];
        } midi;
+       
+       /* misc stuff */
+       int     chip_version;
+       int     max_channels;
+       int     curr_channels;
+       int     speakers;       // number of speakers
+       int     capability;     // HW capability, various for chip versions
+       int     status;         // HW or SW state
+       
+       /* spdif frame counter */
+       int     spdif_counter;
 };
 
+/* flags used for capability */
+#define        CAN_AC3_HW      0x00000001      // 037 or later
+#define        CAN_AC3_SW      0x00000002      // 033 or later
+#define        CAN_AC3         (CAN_AC3_HW | CAN_AC3_SW)
+#define CAN_DUAL_DAC   0x00000004      // 033 or later
+#define        CAN_MULTI_CH_HW 0x00000008      // 039 or later
+#define        CAN_MULTI_CH    (CAN_MULTI_CH_HW | CAN_DUAL_DAC)
+#define        CAN_LINE_AS_REAR        0x00000010      // 033 or later
+#define        CAN_LINE_AS_BASS        0x00000020      // 039 or later
+#define        CAN_MIC_AS_BASS         0x00000040      // 039 or later
+
+/* flags used for status */
+#define        DO_AC3_HW       0x00000001
+#define        DO_AC3_SW       0x00000002
+#define        DO_AC3          (DO_AC3_HW | DO_AC3_SW)
+#define        DO_DUAL_DAC     0x00000004
+#define        DO_MULTI_CH_HW  0x00000008
+#define        DO_MULTI_CH     (DO_MULTI_CH_HW | DO_DUAL_DAC)
+#define        DO_LINE_AS_REAR 0x00000010      // 033 or later
+#define        DO_LINE_AS_BASS 0x00000020      // 039 or later
+#define        DO_MIC_AS_BASS  0x00000040      // 039 or later
+#define        DO_SPDIF_OUT    0x00000100
+#define        DO_SPDIF_IN     0x00000200
+#define        DO_SPDIF_LOOP   0x00000400
+
 /* --------------------------------------------------------------------- */
 
-static struct cm_state *devs = NULL;
-static unsigned long wavetable_mem = 0;
+static struct cm_state *devs;
+static unsigned long wavetable_mem;
 
 /* --------------------------------------------------------------------- */
 
@@ -361,35 +391,76 @@ extern __inline__ unsigned int hweight32(unsigned int w)
 
 /* --------------------------------------------------------------------- */
 
-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+/*
+ * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
+ */
+
+#undef DMABYTEIO
+
+static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
 {
-       count--;
-       outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
-       outw(count, s->iobase + CODEC_CMI_CH0_FRAME2);
-       outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0);
-//     outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       outb((inb(addr) & mask) | value, addr);
+}
+
+static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
+{
+       outw((inw(addr) & mask) | value, addr);
+}
+
+static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
+{
+       outl((inl(addr) & mask) | value, addr);
+}
+
+static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
+{
+       if (addr)
+           outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
+       outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~1, 0);
 }
 
 static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
 {
-       count--;
+       outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
+       outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 1);
+}
+
+static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+{
        outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);
-       outw(count, s->iobase + CODEC_CMI_CH1_FRAME2);
-       outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0);
-//     outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2);
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 0);
+       if (s->status & DO_DUAL_DAC)
+               set_dmadac1(s, 0, count);
+}
+
+static void set_countadc(struct cm_state *s, unsigned count)
+{
+       outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+}
+
+static void set_countdac(struct cm_state *s, unsigned count)
+{
+       outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+       if (s->status & DO_DUAL_DAC)
+           set_countadc(s, count);
 }
 
 extern __inline__ unsigned get_dmadac(struct cm_state *s)
 {
        unsigned int curr_addr;
 
-       if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE))
-               return 0;
-
-       curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
-       curr_addr -= virt_to_bus(s->dma_dac.rawbuf);
+#if 1
+       curr_addr = inw(s->iobase + CODEC_CMI_CH1_FRAME2) + 1;
+       curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
        curr_addr = s->dma_dac.dmasize - curr_addr;
+#else
+       curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
        curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]-1);
+       curr_addr -= s->dma_dac.rawphys;
+#endif
        return curr_addr;
 }
 
@@ -397,22 +468,22 @@ extern __inline__ unsigned get_dmaadc(struct cm_state *s)
 {
        unsigned int curr_addr;
 
-       if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE))
-               return 0;
-
-       curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
-       curr_addr -= virt_to_bus(s->dma_adc.rawbuf);
+#if 1
+       curr_addr = inw(s->iobase + CODEC_CMI_CH0_FRAME2) + 1;
+       curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
        curr_addr = s->dma_adc.dmasize - curr_addr;
+#else
+       curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
        curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]-1);
+       curr_addr -= s->dma_adc.rawphys;
+#endif
        return curr_addr;
 }
 
 static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
 {
        outb(idx, s->iobase + CODEC_SB16_ADDR);
-       udelay(10);
        outb(data, s->iobase + CODEC_SB16_DATA);
-       udelay(10);
 }
 
 static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
@@ -420,33 +491,31 @@ static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
        unsigned char v;
 
        outb(idx, s->iobase + CODEC_SB16_ADDR);
-       udelay(10);
        v = inb(s->iobase + CODEC_SB16_DATA);
-       udelay(10);
        return v;
 }
 
+static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
+{
+       if (mask)
+               s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
+       s->fmt = (s->fmt & mask) | data;
+       outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+}
+
 static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
-       if (mask) {
-               s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
-               udelay(10);
-       }
-       s->fmt = (s->fmt & mask) | data;
-       outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+       set_fmt_unlocked(s,mask,data);
        spin_unlock_irqrestore(&s->lock, flags);
-       udelay(10);
 }
 
 static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
 {
        outb(idx, s->iobase + CODEC_SB16_ADDR);
-       udelay(10);
        outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
-       udelay(10);
 }
 
 static struct {
@@ -463,125 +532,461 @@ static struct {
        { 22050,        (16000 + 22050) / 2,    (22050 + 32000) / 2,    2 },
        { 32000,        (22050 + 32000) / 2,    (32000 + 44100) / 2,    6 },
        { 44100,        (32000 + 44100) / 2,    (44100 + 48000) / 2,    3 },
-       { 48000,        (44100 + 48000) /2,     48000,                  7 }
+       { 48000,        (44100 + 48000) / 2,    48000,                  7 }
 };
 
-static void set_dac_rate(struct cm_state *s, unsigned rate)
+static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
+{
+       if (rate == 48000 || rate == 44100) {
+               // SPDIFI48K SPDF_ACc97
+               maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~0x01008000, rate == 48000 ? 0x01008000 : 0);
+               // ENSPDOUT
+               maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, 0x80);
+               // SPDF_1 SPD2DAC
+               maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x240);
+               // CDPLAY
+               if (s->chip_version >= 39)
+                       maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+               s->status |= DO_SPDIF_OUT;
+       } else {
+               maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0x80, 0);
+               maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0x240, 0);
+               if (s->chip_version >= 39)
+                       maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+               s->status &= ~DO_SPDIF_OUT;
+       }
+}
+
+static void set_spdifout(struct cm_state *s, unsigned rate)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&s->lock, flags);
+       set_spdifout_unlocked(s,rate);
+       spin_unlock_irqrestore(&s->lock, flags);
+}
+
+/* find parity for bit 4~30 */
+static unsigned parity(unsigned data)
+{
+       unsigned parity = 0;
+       int counter = 4;
+
+       data >>= 4;     // start from bit 4
+       while (counter <= 30) {
+               if (data & 1)
+                       parity++;
+               data >>= 1;
+               counter++;
+       }
+       return parity & 1;
+}
+
+static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
+{
+       /* enable AC3 */
+       if (rate == 48000 || rate == 44100) {
+               // mute DAC
+               maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x40);
+               // AC3EN for 037, 0x10
+               maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
+               // AC3EN for 039, 0x04
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x04);
+               if (s->capability & CAN_AC3_HW) {
+                       // SPD24SEL for 037, 0x02
+                       // SPD24SEL for 039, 0x20, but cannot be set
+                       maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
+                       s->status |= DO_AC3_HW;
+                       if (s->chip_version >= 39)
+                               maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+                } else {
+                       // SPD32SEL for 037 & 039, 0x20
+                       maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x20);
+                       // set 176K sample rate to fix 033 HW bug
+                       if (s->chip_version == 33) {
+                               if (rate == 48000)
+                                       maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
+                               else
+                                       maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+                       }
+                       s->status |= DO_AC3_SW;
+               }
+       } else {
+               maskb(s->iobase + CODEC_CMI_MIXER1, ~0x40, 0);
+               maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0x32, 0);
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x24, 0);
+               maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+               if (s->chip_version == 33)
+                       maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+               if (s->chip_version >= 39)
+                       maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+               s->status &= ~DO_AC3;
+       }
+       s->spdif_counter = 0;
+
+}
+
+static void set_ac3(struct cm_state *s, unsigned rate)
 {
        unsigned long flags;
-       unsigned char freq = 4, val;
+
+       spin_lock_irqsave(&s->lock, flags);
+       set_spdifout_unlocked(s, rate);
+       set_ac3_unlocked(s,rate);
+       spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void trans_ac3(struct cm_state *s, void *dest, const char *source, int size)
+{
+       int   i = size / 2;
+       unsigned long data;
+       unsigned long *dst = (unsigned long *) dest;
+       unsigned short *src = (unsigned short *)source;
+
+       do {
+               data = (unsigned long) *src++;
+               data <<= 12;                    // ok for 16-bit data
+               if (s->spdif_counter == 2 || s->spdif_counter == 3)
+                       data |= 0x40000000;     // indicate AC-3 raw data
+               if (parity(data))
+                       data |= 0x80000000;     // parity
+               if (s->spdif_counter == 0)
+                       data |= 3;              // preamble 'M'
+               else if (s->spdif_counter & 1)
+                       data |= 5;              // odd, 'W'
+               else
+                       data |= 9;              // even, 'M'
+               *dst++ = data;
+               s->spdif_counter++;
+               if (s->spdif_counter == 384)
+                       s->spdif_counter = 0;
+       } while (--i);
+}
+
+static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
+{
+       unsigned char freq = 4;
        int     i;
 
        if (rate > 48000)
                rate = 48000;
-       if (rate < 5512)
-               rate = 5512;
-       for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)
-       {
-               if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)
-               {
+       if (rate < 8000)
+               rate = 8000;
+       for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+               if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
                        rate = rate_lookup[i].rate;
                        freq = rate_lookup[i].freq;
                        break;
                }
        }
-       s->ratedac = rate;
+       s->rateadc = rate;
        freq <<= 2;
-       spin_lock_irqsave(&s->lock, flags);
-       val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0x1c; 
-       outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);
-       spin_unlock_irqrestore(&s->lock, flags);
+
+       maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
 }
 
 static void set_adc_rate(struct cm_state *s, unsigned rate)
 {
        unsigned long flags;
-       unsigned char freq = 4, val;
+       unsigned char freq = 4;
        int     i;
 
        if (rate > 48000)
                rate = 48000;
-       if (rate < 5512)
-               rate = 5512;
-       for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)
-       {
-               if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)
-               {
+       if (rate < 8000)
+               rate = 8000;
+       for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+               if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
                        rate = rate_lookup[i].rate;
                        freq = rate_lookup[i].freq;
                        break;
                }
        }
        s->rateadc = rate;
+       freq <<= 2;
+
+       spin_lock_irqsave(&s->lock, flags);
+       maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
+       spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void set_dac_rate(struct cm_state *s, unsigned rate)
+{
+       unsigned long flags;
+       unsigned char freq = 4;
+       int     i;
+
+       if (rate > 48000)
+               rate = 48000;
+       if (rate < 8000)
+               rate = 8000;
+       for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+               if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
+                       rate = rate_lookup[i].rate;
+                       freq = rate_lookup[i].freq;
+                       break;
+               }
+       }
+       s->ratedac = rate;
        freq <<= 5;
+
        spin_lock_irqsave(&s->lock, flags);
-       val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0xe0; 
-       outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);
+       maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0xe0, freq);
+
+
+       if (s->curr_channels <=  2)
+               set_spdifout_unlocked(s, rate);
+       if (s->status & DO_DUAL_DAC)
+               set_adc_rate_unlocked(s, rate);
+
        spin_unlock_irqrestore(&s->lock, flags);
 }
 
 /* --------------------------------------------------------------------- */
+static inline void reset_adc(struct cm_state *s)
+{
+       /* reset bus master */
+       outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+}
+
+static inline void reset_dac(struct cm_state *s)
+{
+       /* reset bus master */
+       outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       if (s->status & DO_DUAL_DAC)
+               reset_adc(s);
+}
+
+static inline void pause_adc(struct cm_state *s)
+{
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 4);
+}
+
+static inline void pause_dac(struct cm_state *s)
+{
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 8);
+       if (s->status & DO_DUAL_DAC)
+               pause_adc(s);
+}
+
+extern inline void disable_adc(struct cm_state *s)
+{
+       /* disable channel */
+       s->enable &= ~CM_ENABLE_CH0;
+       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       reset_adc(s);
+}
+
+extern inline void disable_dac(struct cm_state *s)
+{
+       /* disable channel */
+       s->enable &= ~CM_ENABLE_CH1;
+       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       reset_dac(s);
+       if (s->status & DO_DUAL_DAC)
+               disable_adc(s);
+}
+
+extern inline void enable_adc(struct cm_state *s)
+{
+       if (!(s->enable & CM_ENABLE_CH0)) {
+               /* enable channel */
+               s->enable |= CM_ENABLE_CH0;
+               outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       }
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~4, 0);
+}
+
+extern inline void enable_dac_unlocked(struct cm_state *s)
+{
+       if (!(s->enable & CM_ENABLE_CH1)) {
+               /* enable channel */
+               s->enable |= CM_ENABLE_CH1;
+               outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       }
+       maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~8, 0);
+
+       if (s->status & DO_DUAL_DAC)
+               enable_adc(s);
+}
+
+extern inline void enable_dac(struct cm_state *s)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&s->lock, flags);
+       enable_dac_unlocked(s);
+       spin_unlock_irqrestore(&s->lock, flags);
+}
+
+extern inline void stop_adc_unlocked(struct cm_state *s)
+{
+       if (s->enable & CM_ENABLE_CH0) {
+               /* disable interrupt */
+               maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~1, 0);
+               disable_adc(s);
+       }
+}
 
 extern inline void stop_adc(struct cm_state *s)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
-       /* disable channel */
-       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-       s->enable &= ~CM_CENABLE_RE;
-       /* disable interrupt */
-       outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       /* reset */
-       outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-       udelay(10);
-       outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       stop_adc_unlocked(s);
        spin_unlock_irqrestore(&s->lock, flags);
-}      
+
+}
+
+extern inline void stop_dac_unlocked(struct cm_state *s)
+{
+       if (s->enable & CM_ENABLE_CH1) {
+               /* disable interrupt */
+               maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~2, 0);
+               disable_dac(s);
+       }
+       if (s->status & DO_DUAL_DAC)
+               stop_adc_unlocked(s);
+}
 
 extern inline void stop_dac(struct cm_state *s)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
-       /* disable channel */
-       s->enable &= ~CM_CENABLE_PE;
-       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-       /* disable interrupt */
-       outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       /* reset */
-       outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-       udelay(10);
-       outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       stop_dac_unlocked(s);
        spin_unlock_irqrestore(&s->lock, flags);
-}      
+}
 
-static void start_dac(struct cm_state *s)
+static void start_adc_unlocked(struct cm_state *s)
+{
+       if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+           && s->dma_adc.ready) {
+               /* enable interrupt */
+               maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+               enable_adc(s);
+       }
+}
+
+static void start_adc(struct cm_state *s)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&s->lock, flags);
+       start_adc_unlocked(s);
+       spin_unlock_irqrestore(&s->lock, flags);
+}      
+
+static void start_dac1_unlocked(struct cm_state *s)
+{
+       if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
+               /* enable interrupt */
+//             maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+               enable_dac_unlocked(s);
+       }
+}
+
+//static void start_dac1(struct cm_state *s)
+//{
+//     unsigned long flags;
+//
+//     spin_lock_irqsave(&s->lock, flags);
+//     start_dac1_unlocked(s);
+//     spin_unlock_irqrestore(&s->lock, flags);
+//}    
+
+static void start_dac_unlocked(struct cm_state *s)
+{
        if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
-               outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-               s->enable |= CM_CENABLE_PE;
-               outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+               /* enable interrupt */
+               maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 2);
+               enable_dac_unlocked(s);
        }
+               if (s->status & DO_DUAL_DAC)
+                       start_dac1_unlocked(s);
+}
+
+static void start_dac(struct cm_state *s)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&s->lock, flags);
+       start_dac_unlocked(s);
        spin_unlock_irqrestore(&s->lock, flags);
 }      
 
-static void start_adc(struct cm_state *s)
+static int prog_dmabuf(struct cm_state *s, unsigned rec);
+
+static int set_dac_channels(struct cm_state *s, int channels)
 {
        unsigned long flags;
-
        spin_lock_irqsave(&s->lock, flags);
-       if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
-           && s->dma_adc.ready) {
-               outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-               s->enable |= CM_CENABLE_RE;
-               outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+
+       if ((channels > 2) && (channels <= s->max_channels)
+        && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
+           set_spdifout_unlocked(s, 0);
+           if (s->capability & CAN_MULTI_CH_HW) {
+               // NXCHG
+               maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, 0x80);
+               // CHB3D or CHB3D5C
+               maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, channels > 4 ? 0x80 : 0x20);
+               // CHB3D6C
+               maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, channels == 6 ? 0x80 : 0);
+               // ENCENTER 
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0x80, channels == 6 ? 0x80 : 0);
+               s->status |= DO_MULTI_CH_HW;
+           } else if (s->capability & CAN_DUAL_DAC) {
+               unsigned char fmtm = ~0, fmts = 0;
+               ssize_t ret;
+
+               // ENDBDAC, turn on double DAC mode
+               // XCHGDAC, CH0 -> back, CH1->front
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0xC0);
+               s->status |= DO_DUAL_DAC;
+               // prepare secondary buffer
+
+               spin_unlock_irqrestore(&s->lock, flags);
+               ret = prog_dmabuf(s, 1);
+               spin_lock_irqsave(&s->lock, flags);
+
+               if (ret) return ret;
+               // copy the hw state
+               fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
+               fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
+               // the HW only support 16-bit stereo
+               fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
+               fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
+               fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+               fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+               
+               set_fmt_unlocked(s, fmtm, fmts);
+               set_adc_rate_unlocked(s, s->ratedac);
+
+           }
+           // N4SPK3D, disable 4 speaker mode (analog duplicate)
+           if (s->speakers > 2)
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0x04, 0);
+           s->curr_channels = channels;
+       } else {
+           if (s->status & DO_MULTI_CH_HW) {
+               maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x80, 0);
+               maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, 0);
+               maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, 0);
+           } else if (s->status & DO_DUAL_DAC) {
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x80, 0);
+           }
+           // N4SPK3D, enable 4 speaker mode (analog duplicate)
+           if (s->speakers > 2)
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, 0x04);
+           s->status &= ~DO_MULTI_CH;
+           s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
        }
+
        spin_unlock_irqrestore(&s->lock, flags);
-}      
+       return s->curr_channels;
+}
 
 /* --------------------------------------------------------------------- */
 
@@ -591,7 +996,7 @@ static void start_adc(struct cm_state *s)
 static void dealloc_dmabuf(struct dmabuf *db)
 {
        struct page *pstart, *pend;
-
+       
        if (db->rawbuf) {
                /* undo marking the pages as reserved */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
@@ -603,8 +1008,7 @@ static void dealloc_dmabuf(struct dmabuf *db)
        db->mapped = db->ready = 0;
 }
 
-
-/* Ch0 is used for playback, Ch1 is used for recording */
+/* Ch1 is used for playback, Ch0 is used for recording */
 
 static int prog_dmabuf(struct cm_state *s, unsigned rec)
 {
@@ -617,17 +1021,15 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec)
        unsigned char fmt;
        unsigned long flags;
 
-       spin_lock_irqsave(&s->lock, flags);
        fmt = s->fmt;
        if (rec) {
-               s->enable &= ~CM_CENABLE_RE;
+               stop_adc(s);
                fmt >>= CM_CFMT_ADCSHIFT;
        } else {
-               s->enable &= ~CM_CENABLE_PE;
+               stop_dac(s);
                fmt >>= CM_CFMT_DACSHIFT;
        }
-       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-       spin_unlock_irqrestore(&s->lock, flags);
+
        fmt &= CM_CFMT_MASK;
        db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
        if (!db->rawbuf) {
@@ -638,12 +1040,13 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec)
                if (!db->rawbuf)
                        return -ENOMEM;
                db->buforder = order;
-               if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
-                       printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
-                              virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
-               if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
-                       printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
-                              virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
+               db->rawphys = virt_to_bus(db->rawbuf);
+               if ((db->rawphys ^ (db->rawphys + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
+                       printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
+                              (long) db->rawphys, PAGE_SIZE << db->buforder);
+               if ((db->rawphys + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
+                       printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
+                              (long) db->rawphys, PAGE_SIZE << db->buforder);
                /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
@@ -670,30 +1073,22 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec)
        if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
                db->numfrag = db->ossmaxfrags;
        /* to make fragsize >= 4096 */
-#if 0  
-       if(s->modem)
-       {
-               while (db->fragsize < 4096 && db->numfrag >= 4)
-               {
-                       db->fragsize *= 2;
-                       db->fragshift++;
-                       db->numfrag /= 2;
-               }
-       }
-#endif 
        db->fragsamples = db->fragsize >> sample_shift[fmt];
        db->dmasize = db->numfrag << db->fragshift;
        db->dmasamples = db->dmasize >> sample_shift[fmt];
        memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
        spin_lock_irqsave(&s->lock, flags);
        if (rec) {
-               set_dmaadc(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);
+               if (s->status & DO_DUAL_DAC)
+                   set_dmadac1(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
+               else
+                   set_dmaadc(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
                /* program sample counts */
-               outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+               set_countdac(s, db->fragsamples);
        } else {
-               set_dmadac(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);
+               set_dmadac(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
                /* program sample counts */
-               outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+               set_countdac(s, db->fragsamples);
        }
        spin_unlock_irqrestore(&s->lock, flags);
        db->ready = 1;
@@ -704,6 +1099,7 @@ extern __inline__ void clear_advance(struct cm_state *s)
 {
        unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
        unsigned char *buf = s->dma_dac.rawbuf;
+       unsigned char *buf1 = s->dma_adc.rawbuf;
        unsigned bsize = s->dma_dac.dmasize;
        unsigned bptr = s->dma_dac.swptr;
        unsigned len = s->dma_dac.fragsize;
@@ -711,11 +1107,14 @@ extern __inline__ void clear_advance(struct cm_state *s)
        if (bptr + len > bsize) {
                unsigned x = bsize - bptr;
                memset(buf + bptr, c, x);
+               if (s->status & DO_DUAL_DAC)
+                       memset(buf1 + bptr, c, x);
                bptr = 0;
                len -= x;
        }
        memset(buf + bptr, c, len);
-       outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+       if (s->status & DO_DUAL_DAC)
+               memset(buf1 + bptr, c, len);
 }
 
 /* call with spinlock held! */
@@ -726,7 +1125,29 @@ static void cm_update_ptr(struct cm_state *s)
 
        /* update ADC pointer */
        if (s->dma_adc.ready) {
-               hwptr = (s->dma_adc.dmasize - get_dmaadc(s)) % s->dma_adc.dmasize;
+           if (s->status & DO_DUAL_DAC) {
+               hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
+               diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+               s->dma_adc.hwptr = hwptr;
+               s->dma_adc.total_bytes += diff;
+               if (s->dma_adc.mapped) {
+                       s->dma_adc.count += diff;
+                       if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+                               wake_up(&s->dma_adc.wait);
+               } else {
+                       s->dma_adc.count -= diff;
+                       if (s->dma_adc.count <= 0) {
+                               pause_adc(s);
+                               s->dma_adc.error++;
+                       } else if (s->dma_adc.count <= (signed)s->dma_adc.fragsize && !s->dma_adc.endcleared) {
+                               clear_advance(s);
+                               s->dma_adc.endcleared = 1;
+                       }
+                       if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
+                               wake_up(&s->dma_adc.wait);
+               }
+           } else {
+               hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
                diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
                s->dma_adc.hwptr = hwptr;
                s->dma_adc.total_bytes += diff;
@@ -735,15 +1156,15 @@ static void cm_update_ptr(struct cm_state *s)
                        wake_up(&s->dma_adc.wait);
                if (!s->dma_adc.mapped) {
                        if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-                               s->enable &= ~CM_CENABLE_RE;
-                               outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+                               pause_adc(s);
                                s->dma_adc.error++;
                        }
                }
+           }
        }
        /* update DAC pointer */
        if (s->dma_dac.ready) {
-               hwptr = (s->dma_dac.dmasize - get_dmadac(s)) % s->dma_dac.dmasize;
+               hwptr = get_dmadac(s) % s->dma_dac.dmasize;
                diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
                s->dma_dac.hwptr = hwptr;
                s->dma_dac.total_bytes += diff;
@@ -754,8 +1175,7 @@ static void cm_update_ptr(struct cm_state *s)
                } else {
                        s->dma_dac.count -= diff;
                        if (s->dma_dac.count <= 0) {
-                               s->enable &= ~CM_CENABLE_PE;
-                               outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+                               pause_dac(s);
                                s->dma_dac.error++;
                        } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
                                clear_advance(s);
@@ -767,6 +1187,7 @@ static void cm_update_ptr(struct cm_state *s)
        }
 }
 
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 /* hold spinlock for the following! */
 static void cm_handle_midi(struct cm_state *s)
 {
@@ -796,11 +1217,13 @@ static void cm_handle_midi(struct cm_state *s)
        if (wake)
                wake_up(&s->midi.owait);
 }
+#endif
 
 static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         struct cm_state *s = (struct cm_state *)dev_id;
        unsigned int intsrc, intstat;
+       unsigned char mask = 0;
        
        /* fastpath out, to ease interrupt sharing */
        intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
@@ -810,22 +1233,19 @@ static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
        /* acknowledge interrupt */
        if (intsrc & CM_INT_CH0)
-       {
-               outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-               udelay(10);
-               outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       }
+               mask |= 1;
        if (intsrc & CM_INT_CH1)
-       {
-               outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-               udelay(10);
-               outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-       }
+               mask |= 2;
+       outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+       outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
        cm_update_ptr(s);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
        cm_handle_midi(s);
+#endif
        spin_unlock(&s->lock);
 }
 
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 static void cm_midi_timer(unsigned long data)
 {
        struct cm_state *s = (struct cm_state *)data;
@@ -837,10 +1257,11 @@ static void cm_midi_timer(unsigned long data)
        s->midi.timer.expires = jiffies+1;
        add_timer(&s->midi.timer);
 }
+#endif
 
 /* --------------------------------------------------------------------- */
 
-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
+static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n";
 
 #ifdef CONFIG_SOUND_CMPCI      /* support multiple chips */
 #define VALIDATE_STATE(s)
@@ -874,7 +1295,8 @@ static const struct {
        [SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      DSP_MIX_MICVOLIDX,      MT_5MUTEMONO, 0x01, 0x01 },
        [SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,     DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },
        [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },
-       [SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 }
+       [SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 },
+       [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX,     DSP_MIX_SPKRVOLIDX,     MT_5MUTEMONO, 0x01, 0x01 }
 };
 
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -937,7 +1359,8 @@ static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
        [SOUND_MIXER_MIC]    = 3,
        [SOUND_MIXER_SYNTH]  = 4,
        [SOUND_MIXER_VOLUME] = 5,
-       [SOUND_MIXER_PCM]    = 6
+       [SOUND_MIXER_PCM]    = 6,
+       [SOUND_MIXER_SPEAKER]= 7
 };
 
 #endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
@@ -983,9 +1406,9 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
        }
        if (cmd == OSS_GETVERSION)
                return put_user(SOUND_VERSION, (int *)arg);
-       if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+       if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
                 return -EINVAL;
-        if (_SIOC_DIR(cmd) == _SIOC_READ) {
+        if (_IOC_DIR(cmd) == _IOC_READ) {
                 switch (_IOC_NR(cmd)) {
                 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
                        return put_user(mixer_recmask(s), (int *)arg);
@@ -1033,7 +1456,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
 #endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
                }
        }
-        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 
+        if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
                return -EINVAL;
        s->mix.modcnt++;
        switch (_IOC_NR(cmd)) {
@@ -1100,7 +1523,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
                        rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
                        rr = (rl >> 2) & 7;
                        wrmixer(s, mixtable[i].left, rl<<3);
-                       outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+                       maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
                        break;
                        
                case MT_5MUTEMONO:
@@ -1108,7 +1531,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
                        rl = l < 4 ? 0 : (l - 5) / 3;
                        rr = rl >> 2;
                        wrmixer(s, mixtable[i].left, rl<<3);
-                       outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+                       maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
                        break;
                                
                case MT_5MUTE:
@@ -1117,7 +1540,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
                        wrmixer(s, mixtable[i].left, rl<<3);
                        wrmixer(s, mixtable[i].right, rr<<3);
                        break;
-                               
+
                case MT_6MUTE:
                        if (l < 6)
                                rl = 0x00;
@@ -1187,19 +1610,20 @@ static /*const*/ struct file_operations cm_mixer_fops = {
        release:        cm_release_mixdev,
 };
 
+
 /* --------------------------------------------------------------------- */
 
 static int drain_dac(struct cm_state *s, int nonblock)
 {
-        DECLARE_WAITQUEUE(wait, current);
+       DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        int count, tmo;
 
        if (s->dma_dac.mapped || !s->dma_dac.ready)
                return 0;
+        current->state = TASK_INTERRUPTIBLE;
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
                 spin_lock_irqsave(&s->lock, flags);
                count = s->dma_dac.count;
                 spin_unlock_irqrestore(&s->lock, flags);
@@ -1212,10 +1636,10 @@ static int drain_dac(struct cm_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = (count * HZ) / s->ratedac;
+               tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
                tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
-               if (!schedule_timeout(tmo ? : 1) && tmo)
-                       printk(KERN_DEBUG "cmpci: dma timed out??\n");
+               if (!schedule_timeout(tmo + 1))
+                       printk(KERN_DEBUG "cm: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1263,14 +1687,14 @@ static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *pp
                        if (file->f_flags & O_NONBLOCK)
                                return ret ? ret : -EAGAIN;
                        if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
-                               printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+                               printk(KERN_DEBUG "cm: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
                                       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
                                       s->dma_adc.hwptr, s->dma_adc.swptr);
-                               stop_adc(s);
                                spin_lock_irqsave(&s->lock, flags);
-                               set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples);
+                               stop_adc_unlocked(s);
+                               set_dmaadc(s, s->dma_adc.rawphys, s->dma_adc.dmasamples);
                                /* program sample counts */
-                               outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+                               set_countadc(s, s->dma_adc.fragsamples);
                                s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
                                spin_unlock_irqrestore(&s->lock, flags);
                        }
@@ -1284,11 +1708,11 @@ static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *pp
                spin_lock_irqsave(&s->lock, flags);
                s->dma_adc.swptr = swptr;
                s->dma_adc.count -= cnt;
-               spin_unlock_irqrestore(&s->lock, flags);
                count -= cnt;
                buffer += cnt;
                ret += cnt;
-               start_adc(s);
+               start_adc_unlocked(s);
+               spin_unlock_irqrestore(&s->lock, flags);
        }
        return ret;
 }
@@ -1310,62 +1734,113 @@ static ssize_t cm_write(struct file *file, const char *buffer, size_t count, lof
                return ret;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
+       if (s->status & DO_DUAL_DAC) {
+               if (s->dma_adc.mapped)
+                       return -ENXIO;
+               if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+                       return ret;
+               if (!access_ok(VERIFY_READ, buffer, count))
+                       return -EFAULT;
+       }
        ret = 0;
 #if 0
    spin_lock_irqsave(&s->lock, flags);
    cm_update_ptr(s);
    spin_unlock_irqrestore(&s->lock, flags);
-#endif
+#endif                                                        
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                if (s->dma_dac.count < 0) {
                        s->dma_dac.count = 0;
                        s->dma_dac.swptr = s->dma_dac.hwptr;
                }
+               if (s->status & DO_DUAL_DAC) {
+                       s->dma_adc.swptr = s->dma_dac.swptr;
+                       s->dma_adc.count = s->dma_dac.count;
+                       s->dma_adc.endcleared = s->dma_dac.endcleared;
+               }
                swptr = s->dma_dac.swptr;
                cnt = s->dma_dac.dmasize-swptr;
-               if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-                       cnt = s->dma_dac.dmasize - s->dma_dac.count;
+               if (s->status & DO_AC3_SW) {
+                       if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
+                               cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
+               } else {
+                       if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+                               cnt = s->dma_dac.dmasize - s->dma_dac.count;
+               }
                spin_unlock_irqrestore(&s->lock, flags);
                if (cnt > count)
                        cnt = count;
+               if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
+                   cnt = count / 2;
                if (cnt <= 0) {
                        start_dac(s);
                        if (file->f_flags & O_NONBLOCK)
                                return ret ? ret : -EAGAIN;
                        if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
-                               printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+                               printk(KERN_DEBUG "cm: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
                                       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
                                       s->dma_dac.hwptr, s->dma_dac.swptr);
-                               stop_dac(s);
                                spin_lock_irqsave(&s->lock, flags);
-                               set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples);
+                               stop_dac_unlocked(s);
+                               set_dmadac(s, s->dma_dac.rawphys, s->dma_dac.dmasamples);
                                /* program sample counts */
-                               outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+                               set_countdac(s, s->dma_dac.fragsamples);
                                s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+                               if (s->status & DO_DUAL_DAC)  {
+                                       set_dmadac1(s, s->dma_adc.rawphys, s->dma_adc.dmasamples);
+                                       s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+                               }
                                spin_unlock_irqrestore(&s->lock, flags);
                        }
                        if (signal_pending(current))
                                return ret ? ret : -ERESTARTSYS;
                        continue;
                }
-               if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
-                       return ret ? ret : -EFAULT;
-               swptr = (swptr + cnt) % s->dma_dac.dmasize;
+               if (s->status & DO_AC3_SW) {
+                       // clip exceeded data, caught by 033 and 037
+                       if (swptr + 2 * cnt > s->dma_dac.dmasize)
+                               cnt = (s->dma_dac.dmasize - swptr) / 2;
+                       trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt);
+                       swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
+               } else if (s->status & DO_DUAL_DAC) {
+                       int     i;
+                       unsigned long *src, *dst0, *dst1;
+
+                       src = (unsigned long *) buffer;
+                       dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
+                       dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
+                       // copy left/right sample at one time
+                       for (i = 0; i <= cnt / 4; i++) {
+                               *dst0++ = *src++;
+                               *dst1++ = *src++;
+                       }
+                       swptr = (swptr + cnt) % s->dma_dac.dmasize;
+               } else {
+                       if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+                               return ret ? ret : -EFAULT;
+                       swptr = (swptr + cnt) % s->dma_dac.dmasize;
+               }
                spin_lock_irqsave(&s->lock, flags);
                s->dma_dac.swptr = swptr;
                s->dma_dac.count += cnt;
+               if (s->status & DO_AC3_SW)
+                       s->dma_dac.count += cnt;
                s->dma_dac.endcleared = 0;
                spin_unlock_irqrestore(&s->lock, flags);
                count -= cnt;
                buffer += cnt;
                ret += cnt;
+               if (s->status & DO_DUAL_DAC) {
+                       count -= cnt;
+                       buffer += cnt;
+                       ret += cnt;
+               }
                start_dac(s);
        }
        return ret;
 }
 
-/* No kernel lock - fine (we have our own spinlock) */
 static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct cm_state *s = (struct cm_state *)file->private_data;
@@ -1373,17 +1848,10 @@ static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
        unsigned int mask = 0;
 
        VALIDATE_STATE(s);
-       if (file->f_mode & FMODE_WRITE) {
-               if (!s->dma_dac.ready && prog_dmabuf(s, 0))
-                       return 0;
+       if (file->f_mode & FMODE_WRITE)
                poll_wait(file, &s->dma_dac.wait, wait);
-       }
-       if (file->f_mode & FMODE_READ) {
-               if (!s->dma_adc.ready && prog_dmabuf(s, 1))
-                       return 0;
+       if (file->f_mode & FMODE_READ)
                poll_wait(file, &s->dma_adc.wait, wait);
-       }
-
        spin_lock_irqsave(&s->lock, flags);
        cm_update_ptr(s);
        if (file->f_mode & FMODE_READ) {
@@ -1413,14 +1881,14 @@ static int cm_mmap(struct file *file, struct vm_area_struct *vma)
        VALIDATE_STATE(s);
        lock_kernel();
        if (vma->vm_flags & VM_WRITE) {
-               if ((ret = prog_dmabuf(s, 1)) != 0)
+               if ((ret = prog_dmabuf(s, 0)) != 0)
                        goto out;
                db = &s->dma_dac;
        } else if (vma->vm_flags & VM_READ) {
-               if ((ret = prog_dmabuf(s, 0)) != 0)
+               if ((ret = prog_dmabuf(s, 1)) != 0)
                        goto out;
                db = &s->dma_adc;
-       } else 
+       } else
                goto out;
        ret = -EINVAL;
        if (vma->vm_pgoff != 0)
@@ -1428,7 +1896,7 @@ static int cm_mmap(struct file *file, struct vm_area_struct *vma)
        size = vma->vm_end - vma->vm_start;
        if (size > (PAGE_SIZE << db->buforder))
                goto out;
-       ret = -EAGAIN;
+       ret = -EINVAL;
        if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
                goto out;
        db->mapped = 1;
@@ -1463,13 +1931,15 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, (int *)arg);
                
         case SNDCTL_DSP_RESET:
                if (file->f_mode & FMODE_WRITE) {
                        stop_dac(s);
                        synchronize_irq();
                        s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+                       if (s->status & DO_DUAL_DAC)
+                               s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
                }
                if (file->f_mode & FMODE_READ) {
                        stop_adc(s);
@@ -1479,24 +1949,28 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                return 0;
 
         case SNDCTL_DSP_SPEED:
-                if (get_user(val, (int *)arg))
+               if (get_user(val, (int *)arg))
                        return -EFAULT;
                if (val >= 0) {
                        if (file->f_mode & FMODE_READ) {
-                               stop_adc(s);
+                               spin_lock_irqsave(&s->lock, flags);
+                               stop_adc_unlocked(s);
                                s->dma_adc.ready = 0;
-                               set_adc_rate(s, val);
+                               set_adc_rate_unlocked(s, val);
+                               spin_unlock_irqrestore(&s->lock, flags);
                        }
                        if (file->f_mode & FMODE_WRITE) {
                                stop_dac(s);
                                s->dma_dac.ready = 0;
+                               if (s->status & DO_DUAL_DAC)
+                                       s->dma_adc.ready = 0;
                                set_dac_rate(s, val);
                        }
                }
                return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
-               
+
         case SNDCTL_DSP_STEREO:
-                if (get_user(val, (int *)arg))
+               if (get_user(val, (int *)arg))
                        return -EFAULT;
                fmtd = 0;
                fmtm = ~0;
@@ -1515,12 +1989,19 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                                fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
                        else
                                fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+                       if (s->status & DO_DUAL_DAC) {
+                               s->dma_adc.ready = 0;
+                               if (val)
+                                       fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+                               else
+                                       fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+                       }
                }
                set_fmt(s, fmtm, fmtd);
                return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, (int *)arg))
+               if (get_user(val, (int *)arg))
                        return -EFAULT;
                if (val != 0) {
                        fmtd = 0;
@@ -1540,14 +2021,26 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                                        fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
                                else
                                        fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+                               if (s->status & DO_DUAL_DAC) {
+                                       s->dma_adc.ready = 0;
+                                       if (val >= 2)
+                                               fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+                                       else
+                                               fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+                               }
                        }
                        set_fmt(s, fmtm, fmtd);
-               }
+                       if ((s->capability & CAN_MULTI_CH)
+                            && (file->f_mode & FMODE_WRITE)) {
+                               val = set_dac_channels(s, val);
+                               return put_user(val, (int *)arg);
+                       }
+               }            
                return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) 
                                           : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, (int *)arg);
                
        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+                return put_user(AFMT_S16_LE|AFMT_U8|AFMT_AC3, (int *)arg);
                
        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
                if (get_user(val, (int *)arg))
@@ -1566,27 +2059,47 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                        if (file->f_mode & FMODE_WRITE) {
                                stop_dac(s);
                                s->dma_dac.ready = 0;
-                               if (val == AFMT_S16_LE)
+                               if (val == AFMT_S16_LE || val == AFMT_AC3)
                                        fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
                                else
                                        fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
+                               if (val == AFMT_AC3) {
+                                       fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+                                       set_ac3(s, s->ratedac);
+                               } else
+                                       set_ac3(s, 0);
+                               if (s->status & DO_DUAL_DAC) {
+                                       s->dma_adc.ready = 0;
+                                       if (val == AFMT_S16_LE)
+                                               fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+                                       else
+                                               fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+                               }
                        }
                        set_fmt(s, fmtm, fmtd);
                }
-               return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) 
+               if (s->status & DO_AC3) return put_user(AFMT_AC3, (int *)arg);
+               return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
                                           : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
-               
+
        case SNDCTL_DSP_POST:
                 return 0;
 
         case SNDCTL_DSP_GETTRIGGER:
                val = 0;
-               if (file->f_mode & FMODE_READ && s->enable & CM_CENABLE_RE) 
+               if (s->status & DO_DUAL_DAC) {
+                       if (file->f_mode & FMODE_WRITE &&
+                        (s->enable & CM_ENABLE_CH1) &&
+                        (s->enable & CM_ENABLE_CH0))
+                               val |= PCM_ENABLE_OUTPUT;
+                       return put_user(val, (int *)arg);
+               }
+               if (file->f_mode & FMODE_READ && s->enable & CM_ENABLE_CH0) 
                        val |= PCM_ENABLE_INPUT;
-               if (file->f_mode & FMODE_WRITE && s->enable & CM_CENABLE_PE
+               if (file->f_mode & FMODE_WRITE && s->enable & CM_ENABLE_CH1
                        val |= PCM_ENABLE_OUTPUT;
                return put_user(val, (int *)arg);
-               
+
        case SNDCTL_DSP_SETTRIGGER:
                if (get_user(val, (int *)arg))
                        return -EFAULT;
@@ -1602,6 +2115,10 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                        if (val & PCM_ENABLE_OUTPUT) {
                                if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
                                        return ret;
+                               if (s->status & DO_DUAL_DAC) {
+                                       if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+                                               return ret;
+                               }
                                start_dac(s);
                        } else
                                stop_dac(s);
@@ -1611,22 +2128,22 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
        case SNDCTL_DSP_GETOSPACE:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
-               if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-                       return ret;
+               if (!(s->enable & CM_ENABLE_CH1) && (val = prog_dmabuf(s, 0)) != 0)
+                       return val;
                spin_lock_irqsave(&s->lock, flags);
                cm_update_ptr(s);
                abinfo.fragsize = s->dma_dac.fragsize;
                 abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
                 abinfo.fragstotal = s->dma_dac.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
+                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
                spin_unlock_irqrestore(&s->lock, flags);
                return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
        case SNDCTL_DSP_GETISPACE:
                if (!(file->f_mode & FMODE_READ))
                        return -EINVAL;
-               if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-                       return ret;
+               if (!(s->enable & CM_ENABLE_CH0) && (val = prog_dmabuf(s, 1)) != 0)
+                       return val;
                spin_lock_irqsave(&s->lock, flags);
                cm_update_ptr(s);
                abinfo.fragsize = s->dma_adc.fragsize;
@@ -1643,8 +2160,6 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
         case SNDCTL_DSP_GETODELAY:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
-               if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-                       return ret;
                spin_lock_irqsave(&s->lock, flags);
                cm_update_ptr(s);
                 val = s->dma_dac.count;
@@ -1654,8 +2169,6 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
         case SNDCTL_DSP_GETIPTR:
                if (!(file->f_mode & FMODE_READ))
                        return -EINVAL;
-               if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-                       return ret;
                spin_lock_irqsave(&s->lock, flags);
                cm_update_ptr(s);
                 cinfo.bytes = s->dma_adc.total_bytes;
@@ -1669,8 +2182,6 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
         case SNDCTL_DSP_GETOPTR:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EINVAL;
-               if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-                       return ret;
                spin_lock_irqsave(&s->lock, flags);
                cm_update_ptr(s);
                 cinfo.bytes = s->dma_dac.total_bytes;
@@ -1678,6 +2189,10 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                 cinfo.ptr = s->dma_dac.hwptr;
                if (s->dma_dac.mapped)
                        s->dma_dac.count &= s->dma_dac.fragsize-1;
+               if (s->status & DO_DUAL_DAC) {
+                       if (s->dma_adc.mapped)
+                               s->dma_adc.count &= s->dma_adc.fragsize-1;
+               }
                spin_unlock_irqrestore(&s->lock, flags);
                 return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
@@ -1685,6 +2200,11 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                if (file->f_mode & FMODE_WRITE) {
                        if ((val = prog_dmabuf(s, 0)))
                                return val;
+                       if (s->status & DO_DUAL_DAC) {
+                               if ((val = prog_dmabuf(s, 1)))
+                                       return val;
+                               return put_user(2 * s->dma_dac.fragsize, (int *)arg);
+                       }
                        return put_user(s->dma_dac.fragsize, (int *)arg);
                }
                if ((val = prog_dmabuf(s, 1)))
@@ -1692,7 +2212,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                return put_user(s->dma_adc.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, (int *)arg))
+               if (get_user(val, (int *)arg))
                        return -EFAULT;
                if (file->f_mode & FMODE_READ) {
                        s->dma_adc.ossfragshift = val & 0xffff;
@@ -1713,6 +2233,10 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                                s->dma_dac.ossfragshift = 15;
                        if (s->dma_dac.ossmaxfrags < 4)
                                s->dma_dac.ossmaxfrags = 4;
+                       if (s->status & DO_DUAL_DAC) {
+                               s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
+                               s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
+                       }
                }
                return 0;
 
@@ -1720,14 +2244,17 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
                if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
                    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
                        return -EINVAL;
-                if (get_user(val, (int *)arg))
+               if (get_user(val, (int *)arg))
                        return -EFAULT;
                if (val != 1 && val != 2 && val != 4)
                        return -EINVAL;
                if (file->f_mode & FMODE_READ)
                        s->dma_adc.subdivision = val;
-               if (file->f_mode & FMODE_WRITE)
+               if (file->f_mode & FMODE_WRITE) {
                        s->dma_dac.subdivision = val;
+                       if (s->status & DO_DUAL_DAC)
+                               s->dma_adc.subdivision = val;
+               }
                return 0;
 
         case SOUND_PCM_READ_RATE:
@@ -1742,7 +2269,63 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
         case SOUND_PCM_READ_FILTER:
                return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
 
-        case SOUND_PCM_WRITE_FILTER:
+       case SNDCTL_DSP_GETCHANNELMASK:
+               return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, (int *)arg);
+               
+       case SNDCTL_DSP_BIND_CHANNEL:
+               if (get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val == DSP_BIND_QUERY) {
+                       val = DSP_BIND_FRONT;
+                       if (s->status & DO_SPDIF_OUT)
+                               val |= DSP_BIND_SPDIF;
+                       else {
+                               if (s->curr_channels == 4)
+                                       val |= DSP_BIND_SURR;
+                               if (s->curr_channels > 4)
+                                       val |= DSP_BIND_CENTER_LFE;
+                       }
+               } else {
+                       if (file->f_mode & FMODE_READ) {
+                               stop_adc(s);
+                               s->dma_adc.ready = 0;
+                       }
+                       if (file->f_mode & FMODE_WRITE) {
+                               stop_dac(s);
+                               s->dma_dac.ready = 0;
+                               if (val & DSP_BIND_SPDIF) {
+                                       set_spdifout(s, s->ratedac);
+                                       set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
+                                       if (!(s->status & DO_SPDIF_OUT))
+                                               val &= ~DSP_BIND_SPDIF;
+                               } else {
+                                       int channels;
+                                       int mask;
+
+                                       mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
+                                       switch (mask) {
+                                           case DSP_BIND_FRONT:
+                                               channels = 2;
+                                               break;
+                                           case DSP_BIND_FRONT|DSP_BIND_SURR:
+                                               channels = 4;
+                                               break;
+                                           case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
+                                               channels = 6;
+                                               break;
+                                           default:
+                                               channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
+                                               break;
+                                       }
+                                       set_dac_channels(s, channels);
+                               }
+                       }
+               }
+               return put_user(val, (int *)arg);
+
+       case SOUND_PCM_WRITE_FILTER:
+       case SNDCTL_DSP_MAPINBUF:
+       case SNDCTL_DSP_MAPOUTBUF:
         case SNDCTL_DSP_SETSYNCRO:
                 return -EINVAL;
                
@@ -1788,6 +2371,12 @@ static int cm_open(struct inode *inode, struct file *file)
                        fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
                s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
                set_dac_rate(s, 8000);
+               // clear previous multichannel, spdif, ac3 state
+               set_spdifout(s, 0);
+               if (s->deviceid == PCI_DEVICE_ID_CMEDIA_CM8738) {
+                       set_ac3(s, 0);
+                       set_dac_channels(s, 1);
+               }
        }
        set_fmt(s, fmtm, fmts);
        s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
@@ -1806,11 +2395,23 @@ static int cm_release(struct inode *inode, struct file *file)
        down(&s->open_sem);
        if (file->f_mode & FMODE_WRITE) {
                stop_dac(s);
+#ifndef FIXEDDMA
                dealloc_dmabuf(&s->dma_dac);
+               if (s->status & DO_DUAL_DAC)
+                       dealloc_dmabuf(&s->dma_adc);
+#endif
+               if (s->status & DO_MULTI_CH)
+                       set_dac_channels(s, 0);
+               if (s->status & DO_AC3)
+                       set_ac3(s, 0);
+               if (s->status & DO_SPDIF_OUT)
+                       set_spdifout(s, 0);
        }
        if (file->f_mode & FMODE_READ) {
                stop_adc(s);
+#ifndef FIXEDDMA
                dealloc_dmabuf(&s->dma_adc);
+#endif
        }
        s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
        up(&s->open_sem);
@@ -1831,6 +2432,7 @@ static /*const*/ struct file_operations cm_audio_fops = {
        release:        cm_release,
 };
 
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 /* --------------------------------------------------------------------- */
 
 static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
@@ -1847,12 +2449,9 @@ static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_
                return -ESPIPE;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
-       if (count == 0)
-               return 0;
        ret = 0;
        add_wait_queue(&s->midi.iwait, &wait);
        while (count > 0) {
-               set_current_state(TASK_INTERRUPTIBLE);
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.ird;
                cnt = MIDIINBUF - ptr;
@@ -1862,14 +2461,15 @@ static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK) 
+                       if (file->f_flags & O_NONBLOCK)
                        {
                                if (!ret)
                                        ret = -EAGAIN;
                                break;
                        }
+                       __set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
-                       if (signal_pending(current)) 
+                       if (signal_pending(current))
                        {
                                if (!ret)
                                        ret = -ERESTARTSYS;
@@ -1877,7 +2477,8 @@ static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_
                        }
                        continue;
                }
-               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+               {
                        if (!ret)
                                ret = -EFAULT;
                        break;
@@ -1916,7 +2517,6 @@ static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count
        ret = 0;
        add_wait_queue(&s->midi.owait, &wait);
        while (count > 0) {
-               set_current_state(TASK_INTERRUPTIBLE);
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.owr;
                cnt = MIDIOUTBUF - ptr;
@@ -1928,11 +2528,13 @@ static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK) {
+                       if (file->f_flags & O_NONBLOCK)
+                       {
                                if (!ret)
                                        ret = -EAGAIN;
                                break;
                        }
+                       __set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
                        if (signal_pending(current)) {
                                if (!ret)
@@ -1941,7 +2543,8 @@ static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count
                        }
                        continue;
                }
-               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+               {
                        if (!ret)
                                ret = -EFAULT;
                        break;
@@ -2017,7 +2620,7 @@ static int cm_midi_open(struct inode *inode, struct file *file)
                s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
                s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
                /* enable MPU-401 */
-               outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 4, s->iobase + CODEC_CMI_FUNCTRL1);
+               maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 4);
                outb(0xff, s->iomidi+1); /* reset command */
                if (!(inb(s->iomidi+1) & 0x80))
                        inb(s->iomidi);
@@ -2040,23 +2643,24 @@ static int cm_midi_open(struct inode *inode, struct file *file)
        spin_unlock_irqrestore(&s->lock, flags);
        s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
        up(&s->open_sem);
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
 static int cm_midi_release(struct inode *inode, struct file *file)
 {
        struct cm_state *s = (struct cm_state *)file->private_data;
-        DECLARE_WAITQUEUE(wait, current);
+       DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        unsigned count, tmo;
 
        VALIDATE_STATE(s);
-
        lock_kernel();
+
        if (file->f_mode & FMODE_WRITE) {
+               __set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&s->midi.owait, &wait);
                for (;;) {
-                       set_current_state(TASK_INTERRUPTIBLE);
                        spin_lock_irqsave(&s->lock, flags);
                        count = s->midi.ocnt;
                        spin_unlock_irqrestore(&s->lock, flags);
@@ -2067,11 +2671,12 @@ static int cm_midi_release(struct inode *inode, struct file *file)
                        if (file->f_flags & O_NONBLOCK) {
                                remove_wait_queue(&s->midi.owait, &wait);
                                set_current_state(TASK_RUNNING);
+                               unlock_kernel();
                                return -EBUSY;
                        }
                        tmo = (count * HZ) / 3100;
                        if (!schedule_timeout(tmo ? : 1) && tmo)
-                               printk(KERN_DEBUG "cmpci: midi timed out??\n");
+                               printk(KERN_DEBUG "cm: midi timed out??\n");
                }
                remove_wait_queue(&s->midi.owait, &wait);
                set_current_state(TASK_RUNNING);
@@ -2085,7 +2690,7 @@ static int cm_midi_release(struct inode *inode, struct file *file)
                if (!(inb(s->iomidi+1) & 0x80))
                        inb(s->iomidi);
                /* disable MPU-401 */
-               outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~4, s->iobase + CODEC_CMI_FUNCTRL1);
+               maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~4, 0);
        }
        spin_unlock_irqrestore(&s->lock, flags);
        up(&s->open_sem);
@@ -2103,9 +2708,11 @@ static /*const*/ struct file_operations cm_midi_fops = {
        open:           cm_midi_open,
        release:        cm_midi_release,
 };
+#endif
 
 /* --------------------------------------------------------------------- */
 
+#ifdef CONFIG_SOUND_CMPCI_FM
 static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
        static const unsigned char op_offset[18] = {
@@ -2197,10 +2804,8 @@ static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cm
                outb(5, s->iosynth+2);
                outb(arg & 1, s->iosynth+3);
                return 0;
-
-       default:
-               return -EINVAL;
        }
+       return -EINVAL;
 }
 
 static int cm_dmfm_open(struct inode *inode, struct file *file)
@@ -2236,6 +2841,7 @@ static int cm_dmfm_open(struct inode *inode, struct file *file)
        outb(1, s->iosynth+3);  /* enable OPL3 */
        s->open_mode |= FMODE_DMFM;
        up(&s->open_sem);
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -2267,6 +2873,7 @@ static /*const*/ struct file_operations cm_dmfm_fops = {
        open:           cm_dmfm_open,
        release:        cm_dmfm_release,
 };
+#endif /* CONFIG_SOUND_CMPCI_FM */
 
 /* --------------------------------------------------------------------- */
 
@@ -2285,46 +2892,125 @@ static struct initvol {
        int mixch;
        int vol;
 } initvol[] __initdata = {
-       { SOUND_MIXER_WRITE_CD, 0x4040 },
-       { SOUND_MIXER_WRITE_LINE, 0x4040 },
-       { SOUND_MIXER_WRITE_MIC, 0x4040 },
-       { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
-       { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
-       { SOUND_MIXER_WRITE_PCM, 0x4040 }
+       { SOUND_MIXER_WRITE_CD, 0x4f4f },
+       { SOUND_MIXER_WRITE_LINE, 0x4f4f },
+       { SOUND_MIXER_WRITE_MIC, 0x4f4f },
+       { SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
+       { SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
+       { SOUND_MIXER_WRITE_PCM, 0x4f4f }
 };
 
-#ifdef MODULE
-static int     spdif_loop = 0;
-static int     four_ch = 0;
-static int     rear_out = 0;
-MODULE_PARM(spdif_loop, "i");
-MODULE_PARM(four_ch, "i");
-MODULE_PARM(rear_out, "i");
+/* check chip version and capability */
+static int query_chip(struct cm_state *s)
+{
+       int ChipVersion = -1;
+       unsigned char RegValue;
+
+       // check reg 0Ch, bit 24-31
+       RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
+       if (RegValue == 0) {
+           // check reg 08h, bit 24-28
+           RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
+           RegValue &= 0x1f;
+           if (RegValue == 0) {
+               ChipVersion = 33;
+               s->max_channels = 4;
+               s->capability |= CAN_AC3_SW;
+               s->capability |= CAN_DUAL_DAC;
+           } else {
+               ChipVersion = 37;
+               s->max_channels = 4;
+               s->capability |= CAN_AC3_HW;
+               s->capability |= CAN_DUAL_DAC;
+           }
+       } else {
+           // check reg 0Ch, bit 26
+           if (RegValue & (1 << (26-24))) {
+               ChipVersion = 39;
+               if (RegValue & (1 << (24-24)))
+                   s->max_channels  = 6;
+               else
+                   s->max_channels = 4;
+               s->capability |= CAN_AC3_HW;
+               s->capability |= CAN_DUAL_DAC;
+               s->capability |= CAN_MULTI_CH_HW;
+           } else {
+               ChipVersion = 55; // 4 or 6 channels
+               s->max_channels  = 6;
+               s->capability |= CAN_AC3_HW;
+               s->capability |= CAN_DUAL_DAC;
+               s->capability |= CAN_MULTI_CH_HW;
+           }
+       }
+       // still limited to number of speakers
+       if (s->max_channels > s->speakers)
+               s->max_channels = s->speakers;
+       return ChipVersion;
+}
+
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+static int     mpu_io = CONFIG_SOUND_CMPCI_MPUIO;
 #else
+static int     mpu_io;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+static int     fm_io = CONFIG_SOUND_CMPCI_FMIO;
+#else
+static int     fm_io;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_SPDIFINVERSE
+static int     spdif_inverse = 1;
+#else
+static int     spdif_inverse;
+#endif
 #ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP
-static int     spdif_loop = 1;
+static int     spdif_loop = 1;
 #else
-static int     spdif_loop = 0;
+static int     spdif_loop;
 #endif
-#ifdef CONFIG_SOUND_CMPCI_4CH
-static int     four_ch = 1;
+#ifdef CONFIG_SOUND_CMPCI_SPEAKERS
+static int     speakers = CONFIG_SOUND_CMPCI_SPEAKERS;
 #else
-static int     four_ch = 0;
+static int     speakers = 2;
 #endif
-#ifdef CONFIG_SOUND_CMPCI_REAR
-static int     rear_out = 1;
+#ifdef CONFIG_SOUND_CMPCI_LINE_REAR
+static int     use_line_as_rear = 1;
 #else
-static int     rear_out = 0;
+static int     use_line_as_rear;
 #endif
+#ifdef CONFIG_SOUND_CMPCI_LINE_BASS
+static int     use_line_as_bass = 1;
+#else
+static int     use_line_as_bass;
 #endif
-
-static int __init init_cmpci(void)
+#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+static int     joystick = 1;
+#else
+static int     joystick;
+#endif
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(fm_io, "i");
+MODULE_PARM(spdif_inverse, "i");
+MODULE_PARM(spdif_loop, "i");
+MODULE_PARM(speakers, "i");
+MODULE_PARM(use_line_as_rear, "i");
+MODULE_PARM(use_line_as_bass, "i");
+MODULE_PARM(joystick, "i");
+MODULE_PARM_DESC(mpu_io, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
+MODULE_PARM_DESC(fm_io, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
+MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
+MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
+MODULE_PARM_DESC(speakers, "(2-6) Number of speakers you connect");
+MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
+MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
+MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
+
+void initialize_chip(struct pci_dev *pcidev)
 {
        struct cm_state *s;
-       struct pci_dev *pcidev = NULL;
        mm_segment_t fs;
-       int i, val, index = 0;
-       
+       int i, val;
+       unsigned char reg_mask = 0;
        struct {
                unsigned short  deviceid;
                char            *devicename;
@@ -2333,33 +3019,21 @@ static int __init init_cmpci(void)
                { PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
                { PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
                { PCI_DEVICE_ID_CMEDIA_CM8738,  "CM8738" },
+               { PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
        };
        char    *devicename = "unknown";
-
-#ifdef CONFIG_PCI
-       if (!pci_present())   /* No PCI bus in this machine! */
-#endif
-               return -ENODEV;
-       printk(KERN_INFO "cmpci: version v2.41-nomodem time " __TIME__ " " __DATE__ "\n");
-#if 0
-       if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
-               printk(KERN_INFO "cmpci: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
-#endif
-       while (index < NR_DEVICE && pcidev == NULL && (
-              (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) ||
-              (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)) ||
-              (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) {
+       {
                if (pci_enable_device(pcidev))
-                       continue;
+                       return;
                if (pcidev->irq == 0)
-                       continue;
-               if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) {
-                       printk(KERN_WARNING "cmpci: out of memory\n");
-                       continue;
+                       return;
+               s = kmalloc(sizeof(*s), GFP_KERNEL);
+               if (!s) {
+                       printk(KERN_WARNING "cm: out of memory\n");
+                       return;
                }
                /* search device name */
-               for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++)
-               {
+               for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
                        if (devicetable[i].deviceid == pcidev->device)
                        {
                                devicename = devicetable[i].devicename;
@@ -2376,35 +3050,96 @@ static int __init init_cmpci(void)
                spin_lock_init(&s->lock);
                s->magic = CM_MAGIC;
                s->iobase = pci_resource_start(pcidev, 0);
-               s->iosynth = 0x388;
-               s->iomidi = 0x330;
-               spin_lock_init(&s->lock);
+               s->iosynth = fm_io;
+               s->iomidi = mpu_io;
+               s->status = 0;
+               /* range check */
+               if (speakers < 2)
+                       speakers = 2;
+               else if (speakers > 6)
+                       speakers = 6;
+               s->speakers = speakers;
                if (s->iobase == 0)
-                       continue;
+                       return;
                s->irq = pcidev->irq;
 
                if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
-                       printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+                       printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
                        goto err_region5;
                }
-               if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
-                       printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+               /* disable MPU-401 */
+               maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
+               if (s->iomidi) {
+                   if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
+                       printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
                        s->iomidi = 0;
+                   } else {
+                       /* set IO based at 0x330 */
+                       switch (s->iomidi) {
+                           case 0x330:
+                               reg_mask = 0;
+                               break;
+                           case 0x320:
+                               reg_mask = 0x20;
+                               break;
+                           case 0x310:
+                               reg_mask = 0x40;
+                               break;
+                           case 0x300:
+                               reg_mask = 0x60;
+                               break;
+                           default:
+                               s->iomidi = 0;
+                               break;
+                       }
+                       outb((inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60) | reg_mask, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
+                       /* enable MPU-401 */
+                       if (s->iomidi) {
+                           maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
+                       }
+                   }
                }
-               else
-               {
-                       /* set IO based at 0x330 */
-                       outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
-               }
-               if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
-                       printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+               /* disable FM */
+               maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+               if (s->iosynth) {
+                   if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
+                       printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
                        s->iosynth = 0;
+                   } else {
+                       /* set IO based at 0x388 */
+                       switch (s->iosynth) {
+                           case 0x388:
+                               reg_mask = 0;
+                               break;
+                           case 0x3C8:
+                               reg_mask = 0x01;
+                               break;
+                           case 0x3E0:
+                               reg_mask = 0x02;
+                               break;
+                           case 0x3E8:
+                               reg_mask = 0x03;
+                               break;
+                           default:
+                               s->iosynth = 0;
+                               break;
+                       }
+                       maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
+                       /* enable FM */
+                       if (s->iosynth) {
+                           maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
+                       }
+                   }
                }
+#endif
+               /* enable joystick */
+               if (joystick)
+                       maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
                else
-               {
-                       /* enable FM */
-                       outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
-               }
+                       maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
                /* initialize codec registers */
                outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
                outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
@@ -2413,21 +3148,25 @@ static int __init init_cmpci(void)
 
                /* request irq */
                if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
-                       printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
+                       printk(KERN_ERR "cm: irq %u in use\n", s->irq);
                        goto err_irq;
                }
-               printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n",
+               printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n",
                       devicename, s->iobase, s->irq);
                /* register devices */
                if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0)
                        goto err_dev1;
                if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0)
                        goto err_dev2;
-               if (s->iomidi && (s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+               if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
                        goto err_dev3;
-               if (s->iosynth && (s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+               if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
                        goto err_dev4;
-               pci_set_master(pcidev);
+#endif
+               pci_set_master(pcidev); /* enable bus mastering */
                /* initialize the chips */
                fs = get_fs();
                set_fs(KERNEL_DS);
@@ -2440,59 +3179,78 @@ static int __init init_cmpci(void)
                        val = initvol[i].vol;
                        mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
                }
-               set_fs(fs);
-               if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738)
-               {
+               /* use channel 0 for record, channel 1 for play */
+               maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 1);
+               s->deviceid = pcidev->device;
+               if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) {
+                       /* chip version and hw capability check */
+                       s->chip_version = query_chip(s);
+                       printk(KERN_INFO "chip version = 0%d\n", s->chip_version);
+                       /* seet SPDIF-in inverse before enable SPDIF loop */
+                       if (spdif_inverse) {
+                               /* turn on spdif-in inverse */
+                               maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
+                               printk(KERN_INFO "cm: Inverse SPDIF-in\n");
+                       } else {
+                               /* turn off spdif-ininverse */
+                               maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
+                       }
+
                        /* enable SPDIF loop */
-                       if (spdif_loop)
-                       {
+                       if (spdif_loop) {
+                               s->status |= DO_SPDIF_LOOP;
                                /* turn on spdif-in to spdif-out */
-                               outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 0x80, s->iobase + CODEC_CMI_FUNCTRL1);
-                               printk(KERN_INFO "cmpci: Enable SPDIF loop\n");
+                               maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x80);
+                               printk(KERN_INFO "cm: Enable SPDIF loop\n");
+                       } else {
+                               s->status &= ~DO_SPDIF_LOOP;
+                               /* turn off spdif-in to spdif-out */
+                               maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x80, 0);
                        }
-                       else
-                               outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~0x80, s->iobase + CODEC_CMI_FUNCTRL1);
-                       /* enable 4 channels mode */
-                       if (four_ch)
-                       {
-                               /* 4 channel mode (analog duplicate) */
-                               outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) | 0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
-                               printk(KERN_INFO "cmpci: Enable 4 channels mode\n");
-                               /* has separate rear-out jack ? */
-                               if (rear_out)
-                               {
-                                       /* has separate rear out jack */
-                                       outb(inb(s->iobase + CODEC_CMI_MIXER1) & ~0x20, s->iobase + CODEC_CMI_MIXER1);
-                               }
-                               else
-                               {
-                                       outb(inb(s->iobase + CODEC_CMI_MIXER1) | 0x20, s->iobase + CODEC_CMI_MIXER1);
-                                       printk(KERN_INFO "cmpci: line-in routed as rear-out\n");
-                               }
+                       if (use_line_as_rear) {
+                               s->capability |= CAN_LINE_AS_REAR;
+                               s->status |= DO_LINE_AS_REAR;
+                               maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x20);
+                       } else
+                               maskb(s->iobase + CODEC_CMI_MIXER1, ~0x20, 0);
+                       if (s->chip_version >= 39) {
+                               if (use_line_as_bass) {
+                                       s->capability |= CAN_LINE_AS_BASS;
+                                       s->status |= DO_LINE_AS_BASS;
+                                       maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, 0x60);
+                               } else
+                                       maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x60, 0);
                        }
-                       else
-                               outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) & ~0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+               } else {
+                       /* 8338 will fall here */
+                       s->max_channels = 2;
                }
                /* queue it for later freeing */
                s->next = devs;
                devs = s;
-               index++;
-               continue;
+               return;
 
+#ifdef CONFIG_SOUND_CMPCI_FM
+               unregister_sound_special(s->dev_dmfm);
        err_dev4:
+#endif
+#ifdef CONFIG_SOUND_CMPCI_MIDI
                unregister_sound_midi(s->dev_midi);
        err_dev3:
+#endif
                unregister_sound_mixer(s->dev_mixer);
        err_dev2:
                unregister_sound_dsp(s->dev_audio);
        err_dev1:
-               printk(KERN_ERR "cmpci: cannot register misc device\n");
+               printk(KERN_ERR "cm: cannot register misc device\n");
                free_irq(s->irq, s);
        err_irq:
-               if(s->iosynth)
-                       release_region(s->iosynth, CM_EXTENT_SYNTH);
-               if(s->iomidi)
-                       release_region(s->iomidi, CM_EXTENT_MIDI);
+#ifdef CONFIG_SOUND_CMPCI_FM
+               if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+               if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+#endif
                release_region(s->iobase, CM_EXTENT_CODEC);
        err_region5:
                kfree(s);
@@ -2500,15 +3258,47 @@ static int __init init_cmpci(void)
        if (!devs) {
                if (wavetable_mem)
                        free_pages(wavetable_mem, 20-PAGE_SHIFT);
+               return;
+       }
+       return;
+}
+
+static int __init init_cmpci(void)
+{
+       struct pci_dev *pcidev = NULL;
+       int index = 0;
+
+#ifdef CONFIG_PCI
+       if (!pci_present())   /* No PCI bus in this machine! */
+#endif
                return -ENODEV;
+       printk(KERN_INFO "cm: version $Revision: 5.64 $ time " __TIME__ " " __DATE__ "\n");
+#if 0
+       if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
+               printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
+#endif
+       while (index < NR_DEVICE && (
+              (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) { 
+               initialize_chip(pcidev);
+               index++;
+       }
+       while (index < NR_DEVICE && (
+              (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)))) {
+               initialize_chip(pcidev);
+               index++;
+       }
+       while (index < NR_DEVICE && (
+              (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)))) {
+               initialize_chip(pcidev);
+               index++;
        }
        return 0;
 }
 
 /* --------------------------------------------------------------------- */
 
-MODULE_AUTHOR("ChenLi Tien, cltien@home.com");
-MODULE_DESCRIPTION("CMPCI Audio Driver");
+MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw");
+MODULE_DESCRIPTION("CM8x38 Audio Driver");
 
 static void __exit cleanup_cmpci(void)
 {
@@ -2520,28 +3310,34 @@ static void __exit cleanup_cmpci(void)
                synchronize_irq();
                outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
                free_irq(s->irq, s);
+#ifdef FIXEDDMA
+               dealloc_dmabuf(&s->dma_dac);
+               dealloc_dmabuf(&s->dma_adc);
+#endif
 
                /* reset mixer */
                wrmixer(s, DSP_MIX_DATARESETIDX, 0);
 
                release_region(s->iobase, CM_EXTENT_CODEC);
-               if(s->iomidi)
-               {
-                       release_region(s->iomidi, CM_EXTENT_MIDI);
-                       unregister_sound_midi(s->dev_midi);
-               }
-               if(s->iosynth)
-               {
-                       release_region(s->iosynth, CM_EXTENT_SYNTH);
-                       unregister_sound_special(s->dev_dmfm);
-               }
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+               if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+               if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+#endif
                unregister_sound_dsp(s->dev_audio);
                unregister_sound_mixer(s->dev_mixer);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+               unregister_sound_midi(s->dev_midi);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+               unregister_sound_special(s->dev_dmfm);
+#endif
                kfree(s);
        }
        if (wavetable_mem)
                free_pages(wavetable_mem, 20-PAGE_SHIFT);
-       printk(KERN_INFO "cmpci: unloading\n");
+       printk(KERN_INFO "cm: unloading\n");
 }
 
 module_init(init_cmpci);
index 8e91c35f8ba959f4bdf930513b94008eab826030..4f0de302773dbf9a66d9a947b894d282b0fc4134 100644 (file)
@@ -658,7 +658,7 @@ static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,
               card->pBA0 + BA0_ACCTL);
 
        // Wait for the write to occur.
-       for (count = 0; count < 10; count++) {
+       for (count = 0; count < 100; count++) {
                // First, we want to wait for a short time.
                udelay(25);
                // Now, check to see if the write has completed.
@@ -4463,9 +4463,9 @@ static void __devinit cs4281_remove(struct pci_dev *pci_dev)
        unregister_sound_midi(s->dev_midi);
        iounmap(s->pBA1);
        iounmap(s->pBA0);
-       kfree(s);
        pci_set_drvdata(pci_dev,NULL);
        list_del(&s->list);
+       kfree(s);
        CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
                 "cs4281: cs4281_remove()-: remove successful\n"));
 }
index 969802d671d29908bcd43fcdc43da2ec27f24fbb..55f838bb92e981b0a69bcdde0810abb104c9e043 100644 (file)
@@ -50,6 +50,7 @@
  *     20010409-tw     add hercules game theatre XP amp code.
  *     20010420-tw     cleanup powerdown/up code.
  *     20010521-tw     eliminate pops, and fixes for powerdown.
+ *     20010525-tw     added fixes for thinkpads with powerdown logic.
  *
  *     Status:
  *     Playback/Capture supported from 8k-48k.
@@ -179,7 +180,7 @@ static unsigned long hercules_egpio_disable=0;  /* if non-zero set all EGPIO to
 MODULE_PARM(hercules_egpio_disable, "i");
 static unsigned long initdelay=700;  /* PM delay in millisecs */
 MODULE_PARM(initdelay, "i");
-static unsigned long powerdown=1;  /* turn on/off powerdown processing in driver */
+static unsigned long powerdown=-1;  /* turn on/off powerdown processing in driver */
 MODULE_PARM(powerdown, "i");
 #define DMABUF_DEFAULTORDER 3
 static unsigned long defaultorder=DMABUF_DEFAULTORDER;
@@ -190,6 +191,14 @@ MODULE_PARM(external_amp, "i");
 static int thinkpad;
 MODULE_PARM(thinkpad, "i");
 
+/*
+* set the powerdown module parm to 0 to disable all 
+* powerdown. also set thinkpad to 1 to disable powerdown, 
+* but also to enable the clkrun functionality.
+*/
+static unsigned cs_powerdown=1;
+static unsigned cs_laptop_wait=1;
+
 /* An instance of the 4610 channel */
 struct cs_channel 
 {
@@ -199,7 +208,7 @@ struct cs_channel
 };
 
 #define CS46XX_MAJOR_VERSION "1"
-#define CS46XX_MINOR_VERSION "27"
+#define CS46XX_MINOR_VERSION "28"
 
 #ifdef __ia64__
 #define CS46XX_ARCH            "64"    //architecture key
@@ -284,6 +293,8 @@ struct cs_state {
                int ossmaxfrags;
                unsigned subdivision;
        } dmabuf;
+       /* Guard against mmap/write/read races */
+       struct semaphore sem;
 };
 
 struct cs_card {
@@ -370,8 +381,10 @@ static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int
 static loff_t cs_llseek(struct file *file, loff_t offset, int origin);
 static int cs_hardware_init(struct cs_card *card);
 static int cs46xx_powerup(struct cs_card *card, unsigned int type);
-static int cs461x_powerdown(struct cs_card *card, unsigned int type);
+static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
 static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
+static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
+static void cs46xx_resume_tbl(struct pci_dev *pcidev);
 
 static inline unsigned ld2(unsigned int x)
 {
@@ -688,7 +701,7 @@ static void cs_mute(struct cs_card *card, int state)
 {
        struct ac97_codec *dev=card->ac97_codec[0];
 
-       CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()+ %s\n",
+       CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
                (state == CS_TRUE) ? "Muting" : "UnMuting") );
 
        if(state == CS_TRUE)
@@ -717,7 +730,7 @@ static void cs_mute(struct cs_card *card, int state)
                cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
                cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
        }
-       CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()-\n"));
+       CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
 }
 
 /* set playback sample rate */
@@ -1250,7 +1263,7 @@ static void dealloc_dmabuf(struct cs_state *state)
        dmabuf->SGok = 0;
 }
 
-static int prog_dmabuf(struct cs_state *state)
+static int __prog_dmabuf(struct cs_state *state)
 {
         struct dmabuf *dmabuf = &state->dmabuf;
         unsigned long flags;
@@ -1431,6 +1444,17 @@ static int prog_dmabuf(struct cs_state *state)
        return 1;
 }
 
+static int prog_dmabuf(struct cs_state *state)
+{
+       int ret;
+       
+       down(&state->sem);
+       ret = __prog_dmabuf(state);
+       up(&state->sem);
+       
+       return ret;
+}
+
 static void cs_clear_tail(struct cs_state *state)
 {
 }
@@ -2089,11 +2113,12 @@ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *pp
                return -ESPIPE;
        if (dmabuf->mapped)
                return -ENXIO;
-       if (!dmabuf->ready && (ret = prog_dmabuf(state)))
-               return ret;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
-       ret = 0;
+       
+       down(&state->sem);
+       if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
+               goto out;
 
        add_wait_queue(&state->dmabuf.wait, &wait);
        while (count > 0) {
@@ -2101,8 +2126,8 @@ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *pp
                {
                        schedule();
                        if (signal_pending(current)) {
-                               ret = ret ? ret : -ERESTARTSYS;
-                               break;
+                               if(!ret) ret = -ERESTARTSYS;
+                               goto out;
                        }
                }
                spin_lock_irqsave(&state->card->lock, flags);
@@ -2122,12 +2147,20 @@ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *pp
                        start_adc(state);
                        if (file->f_flags & O_NONBLOCK) {
                                if (!ret) ret = -EAGAIN;
-                               break;
+                               goto out;
                        }
+                       up(&state->sem);
                        schedule();
                        if (signal_pending(current)) {
-                               ret = ret ? ret : -ERESTARTSYS;
-                               break;
+                               if(!ret) ret = -ERESTARTSYS;
+                               goto out;
+                       }
+                       down(&state->sem);
+                       if (dmabuf->mapped) 
+                       {
+                               if(!ret)
+                                       ret = -ENXIO;
+                               goto out;
                        }
                        continue;
                }
@@ -2142,7 +2175,7 @@ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *pp
                        (void *)((unsigned)dmabuf->rawbuf + swptr), cnt, &copied))
                {
                        if (!ret) ret = -EFAULT;
-                       break;
+                       goto out;
                }
                 swptr = (swptr + cnt) % dmabuf->dmasize;
                 spin_lock_irqsave(&card->lock, flags);
@@ -2154,6 +2187,8 @@ static ssize_t cs_read(struct file *file, char *buffer, size_t count, loff_t *pp
                 ret += copied;
                 start_adc(state);
        }
+out:
+       up(&state->sem);
        remove_wait_queue(&state->dmabuf.wait, &wait);
        set_current_state(TASK_RUNNING);
        CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, 
@@ -2183,12 +2218,21 @@ static ssize_t cs_write(struct file *file, const char *buffer, size_t count, lof
 
        if (ppos != &file->f_pos)
                return -ESPIPE;
+
+       down(&state->sem);
        if (dmabuf->mapped)
-               return -ENXIO;
-       if (!dmabuf->ready && (ret = prog_dmabuf(state)))
-               return ret;
+       {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
+               goto out;
        if (!access_ok(VERIFY_READ, buffer, count))
-               return -EFAULT;
+       {
+       ret = -EFAULT;
+       goto out;
+       }
        add_wait_queue(&state->dmabuf.wait, &wait);
        ret = 0;
 /*
@@ -2200,8 +2244,8 @@ static ssize_t cs_write(struct file *file, const char *buffer, size_t count, lof
                {
                        schedule();
                        if (signal_pending(current)) {
-                               ret = ret ? ret : -ERESTARTSYS;
-                               break;
+                               if(!ret) ret = -ERESTARTSYS;
+                               goto out;
                        }
                }
                spin_lock_irqsave(&state->card->lock, flags);
@@ -2234,18 +2278,26 @@ static ssize_t cs_write(struct file *file, const char *buffer, size_t count, lof
                        start_dac(state);
                        if (file->f_flags & O_NONBLOCK) {
                                if (!ret) ret = -EAGAIN;
-                               break;
+                               goto out;
                        }
+                       up(&state->sem);
                        schedule();
                        if (signal_pending(current)) {
-                               ret = ret ? ret : -ERESTARTSYS;
-                               break;
+                               if(!ret) ret = -ERESTARTSYS;
+                               goto out;
                        }
+                       down(&state->sem);
+                       if (dmabuf->mapped)
+                       {
+                               if(!ret)
+                                       ret = -ENXIO;
+                               goto out;
+                       }
                        continue;
                }
                if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
                        if (!ret) ret = -EFAULT;
-                       return ret;
+                       goto out;
                }
                spin_lock_irqsave(&state->card->lock, flags);
                swptr = (swptr + cnt) % dmabuf->dmasize;
@@ -2265,6 +2317,8 @@ static ssize_t cs_write(struct file *file, const char *buffer, size_t count, lof
                ret += cnt;
                start_dac(state);
        }
+out:
+       up(&state->sem);
        remove_wait_queue(&state->dmabuf.wait, &wait);
        set_current_state(TASK_RUNNING);
 
@@ -2352,9 +2406,9 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
        struct cs_card *card = (struct cs_card *)file->private_data;
        struct cs_state *state;
        struct dmabuf *dmabuf;
-       int ret;
+       int ret = 0;
        unsigned long size;
-       
+
        CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=0x%x %s %s\n", 
                (unsigned)file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
                vma->vm_flags & VM_READ ? "VM_READ" : "") );
@@ -2393,24 +2447,39 @@ static int cs_mmap(struct file *file, struct vm_area_struct *vma)
  */
        state = card->states[1];  
        if(!(unsigned)state)
-               return -EINVAL;
+       {
+               ret = -EINVAL;
+               goto out;
+       }
 
+       down(&state->sem);      
        dmabuf = &state->dmabuf;
        if (cs4x_pgoff(vma) != 0)
-               return -EINVAL;
+       {
+               ret = -EINVAL;
+               goto out;
+       }
        size = vma->vm_end - vma->vm_start;
 
        CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
 
        if (size > (PAGE_SIZE << dmabuf->buforder))
-               return -EINVAL;
+       {
+               ret = -EINVAL;
+               goto out;
+       }
        if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
                             size, vma->vm_page_prot))
-               return -EAGAIN;
+       {
+               ret = -EAGAIN;
+               goto out;
+       }
        dmabuf->mapped = 1;
 
        CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
-       return 0;
+out:
+       up(&state->sem);
+       return ret;     
 }
 
 static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -3146,6 +3215,7 @@ static int cs_open(struct inode *inode, struct file *file)
                        if (state == NULL)
                                return -ENOMEM;
                        memset(state, 0, sizeof(struct cs_state));
+                       init_MUTEX(&state->sem);
                        dmabuf = &state->dmabuf;
                        dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
                        if(dmabuf->pbuf==NULL)
@@ -3217,6 +3287,7 @@ static int cs_open(struct inode *inode, struct file *file)
                        if (state == NULL)
                                return -ENOMEM;
                        memset(state, 0, sizeof(struct cs_state));
+                       init_MUTEX(&state->sem);
                        dmabuf = &state->dmabuf;
                        dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
                        if(dmabuf->pbuf==NULL)
@@ -3281,7 +3352,6 @@ static int cs_open(struct inode *inode, struct file *file)
                if((ret = prog_dmabuf(state)))
                        return ret;
        }
-
        CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n") );
        return 0;
 }
@@ -3321,11 +3391,10 @@ static int cs_release(struct inode *inode, struct file *file)
                        state->card->states[state->virt] = NULL;
                        state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
-                       if( (tmp = cs461x_powerdown(card, CS_POWER_DAC )) )
+                       if( (tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE )) )
                        {
                                CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
                                        "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
-                               return -EIO;
                        }
 
                        /* Now turn off external AMP if needed */
@@ -3355,11 +3424,10 @@ static int cs_release(struct inode *inode, struct file *file)
                        state->card->states[state->virt] = NULL;
                        state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
-                       if( (tmp = cs461x_powerdown(card, CS_POWER_ADC )) )
+                       if( (tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE )) )
                        {
                                CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
                                        "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
-                               return -EIO;
                        }
 
                        /* Now turn off external AMP if needed */
@@ -3419,8 +3487,8 @@ static void printpm(struct cs_card *s)
 void cs46xx_ac97_suspend(struct cs_card *card)
 {
        int Count,i;
-       unsigned int tmp;
        struct ac97_codec *dev=card->ac97_codec[0];
+       unsigned int tmp;
 
        CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
 
@@ -3445,7 +3513,6 @@ void cs46xx_ac97_suspend(struct cs_card *card)
 * Save the ac97 volume registers as well as the current powerdown state.
 * Now, mute the all the outputs (master, headphone, and mono), as well
 * as the PCM volume, in preparation for powering down the entire part.
-*/ 
        card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, 
                        (u8)BA0_AC97_MASTER_VOLUME); 
        card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, 
@@ -3454,22 +3521,27 @@ void cs46xx_ac97_suspend(struct cs_card *card)
                        (u8)BA0_AC97_MASTER_VOLUME_MONO); 
        card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, 
                        (u8)BA0_AC97_PCM_OUT_VOLUME);
-               
+*/ 
+/*
+* mute the outputs
+*/
        cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
        cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
        cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
        cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
 
+/*
+* save the registers that cause pops
+*/
        card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL); 
        card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE); 
-
 /*
 * And power down everything on the AC97 codec.
 * well, for now, only power down the DAC/ADC and MIXER VREFON components. 
 * trouble with removing VREF.
 */
        if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-                       CS_POWER_MIXVON )) )
+                       CS_POWER_MIXVON, CS_TRUE )) )
        {
                CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
                        "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) );
@@ -3502,17 +3574,12 @@ void cs46xx_ac97_resume(struct cs_card *card)
 */
        cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE, 
                (u16)card->pm.u32AC97_general_purpose);
-
-       cs_ac97_set(dev, (u8)AC97_POWER_CONTROL, 
-               (u16)card->pm.u32AC97_powerdown);
-       mdelay(10);
-
 /*
 * Now, while the outputs are still muted, restore the state of power
 * on the AC97 part.
 */
        cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
-       mdelay(5);
+       mdelay(5 * cs_laptop_wait);
 /*
 * Restore just the first set of registers, from register number
 * 0x02 to the register number that ulHighestRegToRestore specifies.
@@ -3544,7 +3611,7 @@ static int cs46xx_restart_part(struct cs_card *card)
                dmabuf->ready = 0;
                resync_dma_ptrs(card->states[1]);
                cs_set_divisor(dmabuf);
-               if(prog_dmabuf(card->states[1]))
+               if(__prog_dmabuf(card->states[1]))
                {
                        CS_DBGOUT(CS_PM | CS_ERROR, 1, 
                                printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
@@ -3558,7 +3625,7 @@ static int cs46xx_restart_part(struct cs_card *card)
                dmabuf->ready = 0;
                resync_dma_ptrs(card->states[0]);
                cs_set_divisor(dmabuf);
-               if(prog_dmabuf(card->states[0]))
+               if(__prog_dmabuf(card->states[0]))
                {
                        CS_DBGOUT(CS_PM | CS_ERROR, 1, 
                                printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
@@ -3704,7 +3771,7 @@ static int cs46xx_resume(struct cs_card *card)
                {
                        CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
                                "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
-                       mdelay(10);
+                       mdelay(10 * cs_laptop_wait);
                        cs461x_reset(card);
                        continue;
                }
@@ -3789,12 +3856,13 @@ static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
        if(!(card->pm.flags & CS46XX_PM_IDLE))
                loopcnt = 2000;
        else
-               loopcnt = 500;
+               loopcnt = 500 * cs_laptop_wait;
+       loopcnt *= cs_laptop_wait;
        for (count = 0; count < loopcnt; count++) {
                /*
                 *  First, we want to wait for a short time.
                 */
-               udelay(10);
+               udelay(10 * cs_laptop_wait);
                /*
                 *  Now, check to see if the read has completed.
                 *  ACCTL = 460h, DCV should be reset by now and 460h = 17h
@@ -3819,7 +3887,8 @@ static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
        if(!(card->pm.flags & CS46XX_PM_IDLE))
                loopcnt = 2000;
        else
-               loopcnt = 100;
+               loopcnt = 1000;
+       loopcnt *= cs_laptop_wait;
        for (count = 0; count < loopcnt; count++) {
                /*
                 *  Read the AC97 status register.
@@ -3828,16 +3897,16 @@ static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
                 */
                if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
                        break;
-               udelay(10);
+               udelay(10 * cs_laptop_wait);
        }
        
        /*
         *  Make sure we got valid status.
         */
        if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
-               CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
-                       "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x \n", reg, tmp));
-               CS_DBGOUT(CS_ERROR, 9, printk(KERN_WARNING "returning 0xffff\n"));
+               CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING 
+                       "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n", 
+                               reg, tmp));
                return 0xffff;
        }
 
@@ -3849,7 +3918,7 @@ static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
                "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", 
                        reg, cs461x_peekBA0(card, BA0_ACSDA),
                        cs461x_peekBA0(card, BA0_ACCAD)));
-       return (cs461x_peekBA0(card, BA0_ACSDA));
+       return(cs461x_peekBA0(card, BA0_ACSDA));
 }
 
 static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
@@ -3893,7 +3962,7 @@ static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
                /*
                 *  First, we want to wait for a short time.
                 */
-               udelay(10);
+               udelay(10 * cs_laptop_wait);
                /*
                 *  Now, check to see if the write has completed.
                 *  ACCTL = 460h, DCV should be reset by now and 460h = 07h
@@ -4032,24 +4101,28 @@ static int cs_release_mixdev(struct inode *inode, struct file *file)
                return -ENODEV;
        }
 match:
-       card->active_ctrl(card, -1);
-       card->amplifier_ctrl(card, -1);
        MOD_DEC_USE_COUNT;
        if(!CS_DEC_AND_TEST(&card->mixer_use_cnt))
        {
                CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
                          printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
+               card->active_ctrl(card, -1);
+               card->amplifier_ctrl(card, -1);
                return 0;
        }
 /*
 * ok, no outstanding mixer opens, so powerdown.
 */
-       if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) )
+       if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE )) )
        {
                CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
                        "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) );
+               card->active_ctrl(card, -1);
+               card->amplifier_ctrl(card, -1);
                return -EIO;
        }
+       card->active_ctrl(card, -1);
+       card->amplifier_ctrl(card, -1);
        CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
                  printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
        return 0;
@@ -4341,14 +4414,14 @@ static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
 }
 
 
-static int cs461x_powerdown(struct cs_card *card, unsigned int type)
+static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
 {
        int count;
-       unsigned int tmp=0;
+       unsigned int tmp=0,muted=0;
 
        CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
                "cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
-       if(!powerdown)
+       if(!cs_powerdown && !suspendflag)
        {
                CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
                        "cs46xx: cs461x_powerdown() DISABLED exiting\n"));
@@ -4380,8 +4453,6 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
        type &= ~CS_POWER_MIXVON;
        type &= ~CS_POWER_MIXVOFF;
 
-       cs_mute(card, CS_TRUE);
-
        /*
         *  Power down indicated areas.
         */
@@ -4396,6 +4467,11 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
                        /*
@@ -4439,6 +4515,11 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp |= CS_AC97_POWER_CONTROL_MIXVON;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
                        /*
@@ -4480,6 +4561,11 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (tmp & CS_AC97_POWER_CONTROL_ADC_ON)
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp |= CS_AC97_POWER_CONTROL_ADC;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 
@@ -4524,6 +4610,11 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (tmp & CS_AC97_POWER_CONTROL_DAC_ON)
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp |= CS_AC97_POWER_CONTROL_DAC;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
                        /*
@@ -4557,7 +4648,8 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
                }
        }
        tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
-       cs_mute(card, CS_FALSE);
+       if(muted)
+               cs_mute(card, CS_FALSE);
        CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
                "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
        return 0;
@@ -4566,7 +4658,7 @@ static int cs461x_powerdown(struct cs_card *card, unsigned int type)
 static int cs46xx_powerup(struct cs_card *card, unsigned int type)
 {
        int count;
-       unsigned int tmp=0;
+       unsigned int tmp=0,muted=0;
 
        CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
                "cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
@@ -4578,7 +4670,6 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
        if(type & (CS_POWER_DAC | CS_POWER_ADC))
                type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
 
-       cs_mute(card, CS_TRUE);
        /*
         *  Power up indicated areas.
         */
@@ -4593,6 +4684,11 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON))
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
                        /*
@@ -4636,6 +4732,11 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON))
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
                        /*
@@ -4677,6 +4778,11 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON))
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp &= ~CS_AC97_POWER_CONTROL_ADC;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 
@@ -4721,6 +4827,11 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
                tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
                if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON))
                {
+                       if(!muted)
+                       {
+                               cs_mute(card, CS_TRUE);
+                               muted=1;
+                       }
                        tmp &= ~CS_AC97_POWER_CONTROL_DAC;
                        cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
                        /*
@@ -4754,7 +4865,8 @@ static int cs46xx_powerup(struct cs_card *card, unsigned int type)
                }
        }
        tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
-       cs_mute(card, CS_FALSE);
+       if(muted)
+               cs_mute(card, CS_FALSE);
        CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
                "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
        return 0;
@@ -4843,7 +4955,7 @@ static int cs_hardware_init(struct cs_card *card)
         *  generating bit clock (so we don't try to start the PLL without an
         *  input clock).
         */
-       mdelay(5);              /* 1 should be enough ?? (and pigs might fly) */
+       mdelay(5 * cs_laptop_wait);             /* 1 should be enough ?? (and pigs might fly) */
 
        /*
         *  Set the serial port timing configuration, so that
@@ -4876,7 +4988,7 @@ static int cs_hardware_init(struct cs_card *card)
        /*
          *  Wait until the PLL has stabilized.
         */
-       mdelay(5);              /* Again 1 should be enough ?? */
+       mdelay(5 * cs_laptop_wait);             /* Again 1 should be enough ?? */
 
        /*
         *  Turn on clocking of the core so that we can setup the serial ports.
@@ -4903,7 +5015,7 @@ static int cs_hardware_init(struct cs_card *card)
        cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
 
 
-       mdelay(5);              /* Shouldnt be needed ?? */
+       mdelay(5 * cs_laptop_wait);             /* Shouldnt be needed ?? */
        
 /*
 * If we are resuming under 2.2.x then we can not schedule a timeout.
@@ -4930,7 +5042,7 @@ static int cs_hardware_init(struct cs_card *card)
        {
                for (count = 0; count < 100; count++) {
                // First, we want to wait for a short time.
-                       udelay(25);
+                       udelay(25 * cs_laptop_wait);
 
                        if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
                                break;
@@ -4978,7 +5090,7 @@ static int cs_hardware_init(struct cs_card *card)
        {
                for (count = 0; count < 100; count++) {
                // First, we want to wait for a short time.
-                       udelay(25);
+                       udelay(25 * cs_laptop_wait);
 
                        if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
                                break;
@@ -5068,7 +5180,7 @@ static int cs_hardware_init(struct cs_card *card)
         */
        if(card->pm.flags & CS46XX_PM_IDLE)
        {
-               if(!powerdown)
+               if(!cs_powerdown)
                {
                        if( (tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
                                        CS_POWER_MIXVON )) )
@@ -5081,7 +5193,7 @@ static int cs_hardware_init(struct cs_card *card)
                else
                {
                        if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-                                       CS_POWER_MIXVON )) )
+                                       CS_POWER_MIXVON, CS_FALSE )) )
                        {
                                CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
                                        "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
@@ -5148,6 +5260,7 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
        CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
                  printk(KERN_INFO "cs46xx: probe()+\n"));
 
+       dma_mask = 0xffffffff;  /* this enables playback and recording */
        if (pci_enable_device(pci_dev)) {
                CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
                         "cs46xx: pci_enable_device() failed\n"));
@@ -5169,8 +5282,6 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
                      "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
                return -1;
        }
-       dma_mask = 0xffffffff;  /* this enables playback and recording */
-
        pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
        pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
 
@@ -5239,7 +5350,31 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
                printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
                card->active_ctrl = clkrun_hack;
        }
-       
+/*
+* The thinkpads don't work well without runtime updating on their kernel 
+* delay values (or any laptop with variable CPU speeds really).
+* so, just to be safe set the init delay to 2100.  Eliminates
+* failures on T21 Thinkpads.  remove this code when the udelay
+* and mdelay kernel code is replaced by a pm timer, or the delays
+* work well for battery and/or AC power both.
+*/
+       if(card->active_ctrl == clkrun_hack)
+       {
+               initdelay = 2100;
+               cs_laptop_wait = 5;
+       }
+       if((card->active_ctrl == clkrun_hack) && !(powerdown == 1))
+       {
+/*
+* for some currently unknown reason, powering down the DAC and ADC component
+* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97 
+* codec access problems.  probably the serial clock becomes unsynced. 
+* added code to sync the chips back up, but only helped about 70% the time.
+*/
+               cs_powerdown = 0;
+       }
+       if(powerdown == 0)
+               cs_powerdown = 0;
        card->active_ctrl(card, 1);
 
        /* claim our iospace and irq */
@@ -5290,7 +5425,7 @@ static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
                                        unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
                                        kfree (card->ac97_codec[j]);
                                }
-                       mdelay(10);
+                       mdelay(10 * cs_laptop_wait);
                        continue;
                }
                break;
@@ -5413,7 +5548,7 @@ static void __devinit cs46xx_remove(struct pci_dev *pci_dev)
         *  them.
         */
        if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-                       CS_POWER_MIXVON )) )
+                       CS_POWER_MIXVON, CS_TRUE )) )
        {
                CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
                        "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
@@ -5553,21 +5688,22 @@ int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
        return 0;
 }
 
-static void cs46xx_suspend_tbl(struct pci_dev *pcidev)
+#if CS46XX_ACPI_SUPPORT
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state)
 {
        struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
        CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
                printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
        cs46xx_suspend(s);
-       return;
+       return 0;
 }
 
-static void cs46xx_resume_tbl(struct pci_dev *pcidev)
+static int cs46xx_resume_tbl(struct pci_dev *pcidev)
 {
        struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
        CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
                printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
        cs46xx_resume(s);
-       return;
+       return 0;
 }
-
+#endif
index 46a0158ad1a4e5eec7ed90fa4160ef5411076ffe..9774add1d427aae32dd155935ca62ba61060429e 100644 (file)
@@ -36,8 +36,8 @@
 * for now (12/22/00) only enable the pm_register PM support.
 * allow these table entries to be null.
 */
-static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
-static void cs46xx_resume_tbl(struct pci_dev *pcidev);
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state);
+static int cs46xx_resume_tbl(struct pci_dev *pcidev);
 #define cs_pm_register(a, b, c)  0
 #define cs_pm_unregister_all(a) 
 #define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl
index 46937df71f9645b765bac14988de1163d37841aa..d84598d2962f0adf214f42a9f5bd0909ce14ffdb 100644 (file)
@@ -371,7 +371,7 @@ static struct m3_card *devs = NULL;
  * I'm not very good at laying out functions in a file :)
  */
 static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static void m3_suspend(struct pci_dev *pci_dev);
+static int m3_suspend(struct pci_dev *pci_dev, u32 state);
 static void check_suspend(struct m3_card *card);
 
 struct notifier_block m3_reboot_nb = {m3_notifier, NULL, 0};
@@ -2771,12 +2771,12 @@ static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf
 
     for(card = devs; card != NULL; card = card->next) {
         if(!card->in_suspend)
-            m3_suspend(card->pcidev); /* XXX legal? */
+            m3_suspend(card->pcidev, 3); /* XXX legal? */
     }
     return 0;
 }
 
-static void m3_suspend(struct pci_dev *pci_dev)
+static int m3_suspend(struct pci_dev *pci_dev, u32 state)
 {
     unsigned long flags;
     int i;
@@ -2823,9 +2823,11 @@ static void m3_suspend(struct pci_dev *pci_dev)
     card->in_suspend = 1;
 
     restore_flags(flags);
+
+    return 0;
 }
 
-static void m3_resume(struct pci_dev *pci_dev)
+static int m3_resume(struct pci_dev *pci_dev)
 {
     unsigned long flags;
     int index;
@@ -2904,6 +2906,8 @@ static void m3_resume(struct pci_dev *pci_dev)
      * when we suspended
      */
     wake_up(&card->suspend_queue);
+
+    return 0;
 }
 
 MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
index 458bd57e833507193625bb1637fb5f277f23f7fe..66ba17df77f01e0865ae73ff9929511df78ee597 100644 (file)
@@ -298,6 +298,11 @@ static struct {
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
                0,0,0,0,
                0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+               0,0,0,0,
+               0,1,1,-1},
        {"Sound Blaster Vibra16S", 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
@@ -519,6 +524,9 @@ static struct isapnp_device_id id_table[] __devinitdata = {
        {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
 
+       {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
+
        {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
 
index 9422781c992e3ec4f47b54da6468a471c7949abf..922cd70bd03e40a65f4db4690cb44d45bb6c1f30 100644 (file)
@@ -2045,19 +2045,17 @@ wavefront_oss_ioctl (int devno, unsigned int cmd, caddr_t arg)
 
        switch (cmd) {
        case SNDCTL_SYNTH_INFO:
-               memcpy (&((char *) arg)[0], &wavefront_info,
-                       sizeof (wavefront_info));
+               if(copy_to_user(&((char *) arg)[0], &wavefront_info,
+                       sizeof (wavefront_info)))
+                       return -EFAULT;
                return 0;
-               break;
 
        case SNDCTL_SEQ_RESETSAMPLES:
-               printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
+//             printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
                return 0; /* don't force an error */
-               break;
 
        case SNDCTL_SEQ_PERCMODE:
                return 0; /* don't force an error */
-               break;
 
        case SNDCTL_SYNTH_MEMAVL:
                if ((dev.freemem = wavefront_freemem ()) < 0) {
@@ -2069,10 +2067,11 @@ wavefront_oss_ioctl (int devno, unsigned int cmd, caddr_t arg)
                break;
 
        case SNDCTL_SYNTH_CONTROL:
-               copy_from_user (&wc, arg, sizeof (wc));
-
-               if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
-                       copy_to_user (arg, &wc, sizeof (wc));
+               if(copy_from_user (&wc, arg, sizeof (wc)))
+                       err = -EFAULT;
+               else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+                       if(copy_to_user (arg, &wc, sizeof (wc)))
+                               err = -EFAULT;
                }
 
                return err;
index 490a1f42d1a89f1c00359fd1fe75c3a8479a5c6f..6ad6631dc31a3ff1890accc95c7a16a713f90050 100644 (file)
@@ -591,19 +591,17 @@ wf_mpu_synth_ioctl (int dev,
        switch (cmd) {
 
        case SNDCTL_SYNTH_INFO:
-               copy_to_user (&((char *) arg)[0],
+               if(copy_to_user (&((char *) arg)[0],
                              &wf_mpu_synth_info[index],
-                             sizeof (struct synth_info));
-       
+                             sizeof (struct synth_info)))
+                       return -EFAULT;
                return 0;
-               break;
        
        case SNDCTL_SYNTH_MEMAVL:
                return 0x7fffffff;
-               break;
        
        default:
-               return -(EINVAL);
+               return -EINVAL;
        }
 }
 
index 8ed38f71e62097fdd6e0dc48f554bde9745ff6f0..18e82fdf9ca7d8313ad4b91470a54f4e09523b69 100644 (file)
@@ -4480,9 +4480,15 @@ static int ixj_build_filter_cadence(IXJ *j, IXJ_FILTER_CADENCE * cp)
        if (lcp == NULL)
                return -ENOMEM;
        if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_FILTER_CADENCE)))
+       {
+               kfree(lcp);
                return -EFAULT;
+       }
        if (lcp->filter >= 4)
+       {
+               kfree(lcp);
                return -1;
+       }
        j->cadence_f[lcp->filter].state = 0;
        j->cadence_f[lcp->filter].enable = lcp->enable;
        j->filter_en[lcp->filter] = j->cadence_f[lcp->filter].en_filter = lcp->en_filter;
@@ -4647,13 +4653,18 @@ static void add_caps(IXJ *j)
        }
 }
 
-static int capabilities_check(IXJ *j, struct phone_capability *pcreq)
+static int capabilities_check(IXJ *j, struct phone_capability *u_pcreq)
 {
        int cnt;
        int retval = 0;
+       struct phone_capability pcreq;
+       
+       if(copy_from_user(&pcreq, u_pcreq, sizeof(struct phone_capability)))
+               return -EFAULT;
+               
        for (cnt = 0; cnt < j->caps; cnt++) {
-               if (pcreq->captype == j->caplist[cnt].captype
-                   && pcreq->cap == j->caplist[cnt].cap) {
+               if (pcreq.captype == j->caplist[cnt].captype
+                   && pcreq.cap == j->caplist[cnt].cap) {
                        retval = 1;
                        break;
                }
@@ -4704,7 +4715,8 @@ int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, unsign
                        return -EFAULT;
                break;
        case PHONE_RING_CADENCE:
-               j->ring_cadence = arg;
+               if(get_user(j->ring_cadence, (int *)arg))
+                       return -EFAULT;
                break;
        case IXJCTL_CIDCW:
                if(arg) {
index 0b7d1fdf6bc2cbfe02c33f50e3fecec870777409..1d9abb784200d650272635ea48d75bcfafbfbb64 100644 (file)
@@ -59,6 +59,7 @@ comment 'USB Controllers'
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
 
index 0a63837d8f142ac6d3d04c72ce266947ccc57e50..e63f632ad364447545abe78edc366b6aa5c751c3 100644 (file)
@@ -62,6 +62,7 @@ obj-$(CONFIG_USB_USS720)      += uss720.o
 obj-$(CONFIG_USB_DABUSB)       += dabusb.o
 obj-$(CONFIG_USB_PLUSB)                += plusb.o
 obj-$(CONFIG_USB_OV511)                += ov511.o
+obj-$(CONFIG_USB_SE401)                += se401.o
 obj-$(CONFIG_USB_PEGASUS)      += pegasus.o
 obj-$(CONFIG_USB_CATC)         += catc.o
 obj-$(CONFIG_USB_RIO500)       += rio500.o
index d421fbbbc23130dccc19b999f895cba03dcb2a2d..0927754eda277e204bccf277cf013b4066615e81 100644 (file)
@@ -53,8 +53,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.18 2001/03/18 (C) 1999-2000"
-#define DRIVER_AUTHOR "Petko Manolov <petkan@dce.bg>"
+#define DRIVER_VERSION "v0.4.19 2001/06/07 (C) 1999-2001"
+#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
 #define DRIVER_DESC "ADMtek AN986 Pegasus USB Ethernet driver"
 
 #define        PEGASUS_USE_INTR
@@ -117,8 +117,7 @@ static void ctrl_callback( urb_t *urb )
                        warn( __FUNCTION__ " status %d", urb->status);
        }
        pegasus->flags &= ~ETH_REGS_CHANGED;
-       if ( pegasus->flags & CTRL_URB_SLEEP ) {
-               pegasus->flags &= ~CTRL_URB_SLEEP;
+       if ( waitqueue_active(&pegasus->ctrl_wait) ) {
                wake_up_interruptible( &pegasus->ctrl_wait );
        }
 }
@@ -137,10 +136,9 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        }
        memcpy(buffer,data,size);
        
-       while ( pegasus->flags & ETH_REGS_CHANGED ) {
-               pegasus->flags |= CTRL_URB_SLEEP;
+       while ( pegasus->flags & ETH_REGS_CHANGED )
                interruptible_sleep_on( &pegasus->ctrl_wait );
-       }
+
        pegasus->dr.requesttype = PEGASUS_REQT_READ;
        pegasus->dr.request = PEGASUS_REQ_GET_REGS;
        pegasus->dr.value = cpu_to_le16 (0);
@@ -155,7 +153,6 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 
        add_wait_queue( &pegasus->ctrl_wait, &wait );
        set_current_state( TASK_INTERRUPTIBLE );
-       pegasus->flags |= CTRL_URB_SLEEP;
 
        if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
                err( __FUNCTION__ " BAD CTRLs %d", ret);
@@ -163,11 +160,12 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        }
 
        schedule();
-       remove_wait_queue( &pegasus->ctrl_wait, &wait );
 out:
+       remove_wait_queue( &pegasus->ctrl_wait, &wait );
        memcpy(data,buffer,size);
        kfree(buffer);
-       return  ret;
+
+       return ret;
 }
 
 
@@ -184,10 +182,9 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        }
        memcpy(buffer, data, size);
 
-       while ( pegasus->flags & ETH_REGS_CHANGED ) {
-               pegasus->flags |= CTRL_URB_SLEEP ;
+       while ( pegasus->flags & ETH_REGS_CHANGED )
                interruptible_sleep_on( &pegasus->ctrl_wait );
-       }
+
        pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
        pegasus->dr.request = PEGASUS_REQ_SET_REGS;
        pegasus->dr.value = cpu_to_le16 (0);
@@ -202,19 +199,18 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
                          
        add_wait_queue( &pegasus->ctrl_wait, &wait );
        set_current_state( TASK_INTERRUPTIBLE );
-       pegasus->flags |= CTRL_URB_SLEEP;
 
        if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
                err( __FUNCTION__ " BAD CTRL %d", ret);
-               kfree(buffer);
-               return  ret;
+               goto out;
        }
-
+       
        schedule();
+out:
        remove_wait_queue( &pegasus->ctrl_wait, &wait );
-
        kfree(buffer);
-       return  ret;
+       
+       return ret;
 }
 
 
@@ -232,10 +228,9 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
        }
        memcpy(buffer, &data, 1);
 
-       while ( pegasus->flags & ETH_REGS_CHANGED ) {
-               pegasus->flags |= CTRL_URB_SLEEP;
+       while ( pegasus->flags & ETH_REGS_CHANGED )
                interruptible_sleep_on( &pegasus->ctrl_wait );
-       }
+
        pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
        pegasus->dr.request = PEGASUS_REQ_SET_REG;
        pegasus->dr.value = cpu_to_le16p( &dat);
@@ -250,19 +245,18 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
 
        add_wait_queue( &pegasus->ctrl_wait, &wait );
        set_current_state( TASK_INTERRUPTIBLE );
-       pegasus->flags |= CTRL_URB_SLEEP;
 
        if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
                err( __FUNCTION__ " BAD CTRL %d", ret);
-               kfree(buffer);
-               return  ret;
+               goto out;
        }
 
        schedule();
+out:
        remove_wait_queue( &pegasus->ctrl_wait, &wait );
-
        kfree(buffer);
-       return  ret;
+
+       return ret;
 }
 
 
@@ -451,7 +445,7 @@ static inline int reset_mac( pegasus_t *pegasus )
                return 1;
 
        if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-            usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK1 ) {
+            usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
                __u16   auxmode;
 
                read_mii_word( pegasus, 0, 0x1b, &auxmode );
@@ -797,7 +791,6 @@ static void pegasus_set_multicast( struct net_device *net )
        } else {
                pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
                pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
-               info("%s: set Rx mode", net->name);
        }
 
        pegasus->flags |= ETH_REGS_CHANGE;
index f9ab77dae460f6fb742ff36306519a78fb40f359..182d27a1086ac2b05cc086641cb4720d5ea20627 100644 (file)
@@ -128,30 +128,51 @@ struct usb_eth_dev {
 };
 
 #define        VENDOR_3COM             0x0506
-#define VENDOR_ACCTON           0x083a
-#define VENDOR_ADMTEK           0x07a6
-#define VENDOR_BILLIONTON       0x08dd
-#define VENDOR_COREGA           0x07aa
-#define VENDOR_DLINK1           0x2001
-#define VENDOR_DLINK2           0x07b8
-#define VENDOR_IODATA           0x04bb
-#define VENDOR_LANEED           0x056e
-#define VENDOR_LINKSYS          0x066b
-#define VENDOR_MELCO            0x0411
-#define VENDOR_SMARTBRIDGES    0x08d1
-#define VENDOR_SMC              0x0707
-#define VENDOR_SOHOWARE         0x15e8
+#define        VENDOR_ABOCOM           0x07b8
+#define        VENDOR_ACCTON           0x083a
+#define        VENDOR_ADMTEK           0x07a6
+#define        VENDOR_BILLIONTON       0x08dd
+#define        VENDOR_COREGA           0x07aa
+#define        VENDOR_DLINK            0x2001
+#define        VENDOR_ELSA             0x05cc
+#define        VENDOR_IODATA           0x04bb
+#define        VENDOR_LANEED           0x056e
+#define        VENDOR_LINKSYS          0x066b
+#define        VENDOR_MELCO            0x0411
+#define        VENDOR_SMARTBRIDGES     0x08d1
+#define        VENDOR_SMC              0x0707
+#define        VENDOR_SOHOWARE         0x15e8
 
 #else  /* PEGASUS_DEV */
 
 PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
                DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
+               DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
+               DEFAULT_GPIO_RESET | PEGASUS_II )       
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
                DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
                VENDOR_ADMTEK, 0x8511,
                DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)",
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
                VENDOR_ADMTEK, 0x0986,
                DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
@@ -164,24 +185,32 @@ PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
                DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4001,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
                LINKSYS_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4002,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
                LINKSYS_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK1, 0x4003,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
+               LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
+               LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
+               LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
                DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK1, 0xabc1,
+PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
                DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DU-E10", VENDOR_DLINK2, 0xabc1,
+PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
                DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DU-E100", VENDOR_DLINK2, 0x4002,
-               DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "FiberLine USB", VENDOR_DLINK2, 0x4102,
-               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
                DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
                DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
                LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
@@ -190,8 +219,16 @@ PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
                LINKSYS_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
                LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB USB10TX", VENDOR_LINKSYS, 0x400b,
+               LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
+               LINKSYS_GPIO_RESET | PEGASUS_II )       
 PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
                DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
+               DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
diff --git a/drivers/usb/se401.c b/drivers/usb/se401.c
new file mode 100644 (file)
index 0000000..541bf8c
--- /dev/null
@@ -0,0 +1,1675 @@
+/*
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ * 
+ * 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.
+ *
+ *
+ * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
+ * their chipset available and supporting me while writing this driver.
+ *     - Jeroen Vreeken
+ */
+
+static const char version[] = "0.22";
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/usb.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
+#define virt_to_page(arg)      MAP_NR(arg)
+#define vmalloc_32             vmalloc
+#endif
+
+#include "se401.h"
+
+static int flickerless=0;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
+static __devinitdata struct usb_device_id device_table [] = {
+       { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
+       { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
+       { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
+       { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
+       { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+#endif
+
+static int video_nr = -1;
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("SE401 USB Camera Driver");
+MODULE_PARM(flickerless, "i");
+MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+EXPORT_NO_SYMBOLS;
+
+
+static struct usb_driver se401_driver;
+
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+       unsigned long ret = 0UL;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+
+       if (!pgd_none(*pgd)) {
+               pmd = pmd_offset(pgd, adr);
+               if (!pmd_none(*pmd)) {
+                       ptep = pte_offset(pmd, adr);
+                       pte = *ptep;
+                       if (pte_present(pte)) {
+                               ret = (unsigned long) page_address(pte_page(pte));
+                               ret |= (adr & (PAGE_SIZE - 1));
+                       }
+               }
+       }
+
+       return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long va, kva, ret;
+
+       va = VMALLOC_VMADDR(adr);
+       kva = uvirt_to_kva(pgd_offset_k(va), va);
+       ret = __pa(kva);
+       return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr, page;
+
+       /* Round it off to PAGE_SIZE */
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               page = kvirt_to_pa(adr);
+               mem_map_reserve(virt_to_page(__va(page)));
+               adr += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr, page;
+
+       if (!mem)
+               return;
+
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       adr=(unsigned long) mem;
+       while (size > 0) {
+               page = kvirt_to_pa(adr);
+               mem_map_unreserve(virt_to_page(__va(page)));
+               adr += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       vfree(mem);
+}
+
+
+
+/****************************************************************************
+ *
+ * /proc interface
+ *
+ ***************************************************************************/
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *se401_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int se401_read_proc(char *page, char **start, off_t off, int count,
+                          int *eof, void *data)
+{
+       char *out = page;
+       int i, len;
+       struct usb_se401 *se401 = data;
+       
+       /* Stay under PAGE_SIZE or else bla bla bla.... */
+
+       out+=sprintf(out, "driver_version  : %s\n", version);
+       out+=sprintf(out, "model           : %s\n", se401->camera_name);
+       out+=sprintf(out, "in use          : %s\n", YES_NO (se401->user));
+       out+=sprintf(out, "streaming       : %s\n", YES_NO (se401->streaming));
+       out+=sprintf(out, "button state    : %s\n", YES_NO (se401->button));
+       out+=sprintf(out, "button pressed  : %s\n", YES_NO (se401->buttonpressed));
+       out+=sprintf(out, "num_frames      : %d\n", SE401_NUMFRAMES);
+
+       out+=sprintf(out, "Sizes           :");
+       for (i=0; i<se401->sizes; i++) {
+               out+=sprintf(out, " %dx%d", se401->width[i],
+                   se401->height[i]);
+       }
+       out+=sprintf(out, "\n");
+       
+       out+=sprintf(out, "Frames total    : %d\n", se401->readcount);
+       out+=sprintf(out, "Frames read     : %d\n", se401->framecount);
+       out+=sprintf(out, "Packets dropped : %d\n", se401->dropped);
+       out+=sprintf(out, "Decoding Errors : %d\n", se401->error);
+
+       len = out - page;
+       len -= off;
+       if (len < count) {
+               *eof = 1;
+                       if (len <= 0) return 0;
+       } else
+               len = count;
+
+       *start = page + off;
+       
+       return len;     
+}
+
+static int se401_write_proc(struct file *file, const char *buffer, 
+                           unsigned long count, void *data)
+{
+       return -EINVAL;
+}
+
+static void create_proc_se401_cam (struct usb_se401 *se401)
+{
+       char name[7];
+       struct proc_dir_entry *ent;
+
+       if (!se401_proc_entry || !se401)
+               return;
+
+       sprintf (name, "video%d", se401->vdev.minor);
+
+       ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+                               se401_proc_entry);
+
+       if (!ent)
+               return;
+
+       ent->data = se401;
+       ent->read_proc = se401_read_proc;
+       ent->write_proc = se401_write_proc;
+       se401->proc_entry = ent;
+}
+
+static void destroy_proc_se401_cam (struct usb_se401 *se401)
+{
+       /* One to much, just to be sure :) */
+       char name[9];
+
+       if (!se401 || !se401->proc_entry)
+               return;
+       
+       sprintf(name, "video%d", se401->vdev.minor);
+       remove_proc_entry(name, se401_proc_entry);
+       se401->proc_entry = NULL;
+}
+
+static void proc_se401_create (void)
+{
+       if (video_proc_entry == NULL) {
+               err("/proc/video/ doesn't exist");
+               return;
+       }
+
+       se401_proc_entry=create_proc_entry("se401", S_IFDIR, video_proc_entry);
+
+       if (se401_proc_entry)
+               se401_proc_entry->owner = THIS_MODULE;
+       else
+               err("Unable to initialize /proc/video/se401");
+}
+
+static void proc_se401_destroy(void)
+{
+       if (se401_proc_entry == NULL)
+               return;
+
+       remove_proc_entry("se401", video_proc_entry);
+}
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
+
+
+/****************************************************************************
+ *
+ * se401 register read/write functions
+ *
+ ***************************************************************************/
+
+static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
+                        unsigned short value, unsigned char *cp, int size)
+{
+       return usb_control_msg (
+                se401->dev,
+                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
+                req,
+                (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                value,
+                0,
+                cp,
+                size,
+                HZ
+        );
+}
+
+static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
+                            unsigned short param)
+{
+       /* specs say that the selector (address) should go in the value field
+          and the param in index, but in the logs of the windows driver they do
+          this the other way around...
+        */
+       return usb_control_msg (
+               se401->dev,
+               usb_sndctrlpipe(se401->dev, 0),
+               SE401_REQ_SET_EXT_FEATURE,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               param,
+               selector,
+                NULL,
+                0,
+                HZ
+        );
+}
+
+static unsigned short se401_get_feature(struct usb_se401 *se401, 
+                                       unsigned short selector)
+{
+       /* For 'set' the selecetor should be in index, not sure if the spec is
+          wrong here to....
+        */
+       unsigned char cp[2];
+        usb_control_msg (
+                se401->dev,
+                usb_rcvctrlpipe(se401->dev, 0),
+                SE401_REQ_GET_EXT_FEATURE,
+                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               0,
+                selector,
+                cp,
+                2,
+                HZ
+        );
+       return cp[0]+cp[1]*256;
+}
+
+/****************************************************************************
+ *
+ * Camera control
+ *
+ ***************************************************************************/
+
+
+static int se401_send_pict(struct usb_se401 *se401)
+{
+       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
+       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
+       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
+       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
+       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
+       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+               
+       return 0;
+}
+
+static void se401_set_exposure(struct usb_se401 *se401, int brightness)
+{
+       int integration=brightness<<5;
+       
+       if (flickerless==50) {
+               integration=integration-integration%106667;
+       }
+       if (flickerless==60) {
+               integration=integration-integration%88889;
+       }
+       se401->brightness=integration>>5;
+       se401->expose_h=(integration>>16)&0xff;
+       se401->expose_m=(integration>>8)&0xff;
+       se401->expose_l=integration&0xff;
+}
+
+static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+       p->brightness=se401->brightness;
+       if (se401->enhance) {
+               p->whiteness=32768;
+       } else {
+               p->whiteness=0;
+       }
+       p->colour=65535;
+       p->contrast=65535;
+       p->hue=se401->rgain<<10;
+       p->palette=se401->palette;
+       p->depth=3; /* rgb24 */
+       return 0;
+}
+
+
+static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+       if (p->palette != VIDEO_PALETTE_RGB24)
+               return 1;
+       se401->palette=p->palette;
+       if (p->hue!=se401->hue) {
+               se401->rgain= p->hue>>10;
+               se401->bgain= 0x40-(p->hue>>10);
+               se401->hue=p->hue;
+       }
+       if (p->brightness!=se401->brightness) {
+               se401_set_exposure(se401, p->brightness);
+       }
+       if (p->whiteness>=32768) {
+               se401->enhance=1;
+       } else {
+               se401->enhance=0;
+       }
+       se401_send_pict(se401);
+       se401_send_pict(se401);
+       return 0;
+}
+
+/*
+       Hyundai have some really nice docs about this and other sensor related
+       stuff on their homepage: www.hei.co.kr
+*/
+static void se401_auto_resetlevel(struct usb_se401 *se401)
+{
+       unsigned int ahrc, alrc;
+       int oldreset=se401->resetlevel;
+
+       /* For some reason this normally read-only register doesn't get reset
+          to zero after reading them just once...
+        */
+       se401_get_feature(se401, HV7131_REG_HIREFNOH); 
+       se401_get_feature(se401, HV7131_REG_HIREFNOL);
+       se401_get_feature(se401, HV7131_REG_LOREFNOH);
+       se401_get_feature(se401, HV7131_REG_LOREFNOL);
+       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + 
+           se401_get_feature(se401, HV7131_REG_HIREFNOL);
+       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+           se401_get_feature(se401, HV7131_REG_LOREFNOL);
+
+       /* Not an exact science, but it seems to work pretty well... */
+       if (alrc > 10) {
+               while (alrc>=10 && se401->resetlevel < 63) {
+                       se401->resetlevel++;
+                       alrc /=2;
+               }
+       } else if (ahrc > 20) {
+               while (ahrc>=20 && se401->resetlevel > 0) {
+                       se401->resetlevel--;
+                       ahrc /=2;
+               }
+       }
+       if (se401->resetlevel!=oldreset)
+               se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+
+       return;
+}
+
+/* irq handler for snapshot button */
+static void se401_button_irq(struct urb *urb)
+{
+       struct usb_se401 *se401=urb->context;
+       
+       if (!urb) {
+               info("ohoh: null urb");
+               return;
+       }
+       if (!se401->dev) {
+               info("ohoh: device vapourished");
+               return;
+       }
+       
+       if (urb->actual_length >=2 && !urb->status) {
+               if (se401->button)
+                       se401->buttonpressed=1;
+       }
+}
+
+static void se401_video_irq(struct urb *urb)
+{
+       struct usb_se401 *se401=urb->context;
+       int length=urb->actual_length;
+
+       /* ohoh... */
+       if (!se401->streaming) {
+               return;
+       }
+       if (!urb) {
+               info ("ohoh: null urb");
+               return;
+       }
+       if (!se401->dev) {
+               info ("ohoh: device vapourished");
+               return;
+       }
+
+       /* 0 sized packets happen if we are to fast, but sometimes the camera
+          keeps sending them forever...
+        */
+       if (length && !urb->status) {
+               se401->nullpackets=0;
+               switch(se401->scratch[se401->scratch_next].state) {
+                       case BUFFER_READY:
+                       case BUFFER_BUSY: {
+                               se401->dropped++;
+                               break;
+                       }
+                       case BUFFER_UNUSED: {
+                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
+                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
+                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
+                               se401->scratch[se401->scratch_next].length=length;
+                               if (waitqueue_active(&se401->wq)) {
+                                       wake_up_interruptible(&se401->wq);
+                               }
+                               se401->scratch_overflow=0;
+                               se401->scratch_next++;
+                               if (se401->scratch_next>=SE401_NUMSCRATCH)
+                                       se401->scratch_next=0;;
+                               break;
+                       }
+               }
+               se401->bayeroffset+=length;
+               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
+                       se401->bayeroffset=0;
+               }
+       } else {
+               se401->nullpackets++;
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+                       if (waitqueue_active(&se401->wq)) {
+                               wake_up_interruptible(&se401->wq);
+                       }               
+               }
+       }
+
+       /* Resubmit urb for new data */
+       urb->status=0;
+       urb->dev=se401->dev;
+       if(usb_submit_urb(urb))
+               info("urb burned down");
+       return;
+}
+
+static void se401_send_size(struct usb_se401 *se401, int width, int height)
+{
+       int i=0;
+       int mode=0x03; /* No compression */
+       int sendheight=height;
+       int sendwidth=width;
+
+       /* JangGu compression can only be used with the camera supported sizes,
+          but bayer seems to work with any size that fits on the sensor.
+          We check if we can use compression with the current size with either
+          4 or 16 times subcapturing, if not we use uncompressed bayer data
+          but this will result in cutouts of the maximum size....
+        */
+       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+               i++;
+       while (i<se401->sizes) {
+               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
+                       sendheight=se401->height[i];
+                       sendwidth=se401->width[i];
+                       mode=0x40;
+               }
+               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
+                       sendheight=se401->height[i];
+                       sendwidth=se401->width[i];
+                       mode=0x42;
+               }
+               i++;
+       }
+
+       se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
+       se401_set_feature(se401, SE401_OPERATINGMODE, mode);
+
+       if (mode==0x03) {
+               se401->format=FMT_BAYER;
+       } else {
+               se401->format=FMT_JANGGU;
+       }
+
+       return;
+}
+
+/*
+       In this function se401_send_pict is called several times,
+       for some reason (depending on the state of the sensor and the phase of
+       the moon :) doing this only in either place doesn't always work...
+*/
+static int se401_start_stream(struct usb_se401 *se401)
+{
+       urb_t *urb;
+       int err=0, i;
+       se401->streaming=1;
+
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+       /* Set picture settings */
+       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+       se401_send_pict(se401);
+
+       se401_send_size(se401, se401->cwidth, se401->cheight);
+
+       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+       /* Do some memory allocation */
+       for (i=0; i<SE401_NUMFRAMES; i++) {
+               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
+               se401->frame[i].curpix=0;
+       }
+       for (i=0; i<SE401_NUMSBUF; i++) {
+               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       }
+
+       se401->bayeroffset=0;
+       se401->scratch_next=0;
+       se401->scratch_use=0;
+       se401->scratch_overflow=0;
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+               se401->scratch[i].state=BUFFER_UNUSED;
+       }
+
+       for (i=0; i<SE401_NUMSBUF; i++) {
+               urb=usb_alloc_urb(0);
+               if(!urb)
+                       return ENOMEM;
+
+               FILL_BULK_URB(urb, se401->dev,
+                       usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
+                       se401->sbuf[i].data, SE401_PACKETSIZE,
+                       se401_video_irq,
+                       se401);
+               urb->transfer_flags |= USB_QUEUE_BULK;
+
+               se401->urb[i]=urb;
+
+               err=usb_submit_urb(se401->urb[i]);
+               if(err)
+                       err("urb burned down");
+       }
+
+       se401->framecount=0;
+
+       return 0;
+}
+
+static int se401_stop_stream(struct usb_se401 *se401)
+{
+       int i;
+
+       if (!se401->streaming || !se401->dev)
+               return 1;
+
+       se401->streaming=0;
+
+       se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+
+       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+               se401->urb[i]->next=NULL;
+               usb_unlink_urb(se401->urb[i]);
+               usb_free_urb(se401->urb[i]);
+               se401->urb[i]=NULL;
+               kfree(se401->sbuf[i].data);
+       }
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               kfree(se401->scratch[i].data);
+               se401->scratch[i].data=NULL;
+       }
+
+       return 0;
+}
+
+static int se401_set_size(struct usb_se401 *se401, int width, int height)
+{
+       int wasstreaming=se401->streaming;
+       /* Check to see if we need to change */
+       if (se401->cwidth==width && se401->cheight==height)
+               return 0;
+
+       /* Check for a valid mode */
+       if (!width || !height)
+               return 1;
+       if ((width & 1) || (height & 1))
+               return 1;
+       if (width>se401->width[se401->sizes-1])
+               return 1;
+       if (height>se401->height[se401->sizes-1])
+               return 1;
+
+       /* Stop a current stream and start it again at the new size */
+       if (wasstreaming)
+               se401_stop_stream(se401);
+       se401->cwidth=width;
+       se401->cheight=height;
+       if (wasstreaming)
+               se401_start_stream(se401);
+       return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video Decoding
+ *
+ ***************************************************************************/
+
+/*
+       This shouldn't really be done in a v4l driver....
+       But it does make the image look a lot more usable.
+       Basicly it lifts the dark pixels more than the light pixels.
+*/
+static inline void enhance_picture(unsigned char *frame, int len)
+{
+       while (len--) {
+               *frame++=(((*frame^255)*(*frame^255))/255)^255;
+       }
+}
+
+static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
+{
+       struct se401_frame *frame=&se401->frame[se401->curframe];
+       int linelength=se401->cwidth*3;
+
+       if (frame->curlinepix >= linelength) {
+               frame->curlinepix=0;
+               frame->curline+=linelength;
+       }
+
+       /* First three are absolute, all others relative.
+        * Format is rgb from right to left (mirrorred image), 
+        * we flip it to get bgr from left to right. */
+       if (frame->curlinepix < 3) {
+               *(frame->curline-frame->curlinepix)=1+data*4;
+       } else {
+               *(frame->curline-frame->curlinepix)=
+                   *(frame->curline-frame->curlinepix+3)+data*4;
+       }
+       frame->curlinepix++;
+}
+
+static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+{
+       int pos=0;
+       int vlc_cod=0;
+       int vlc_size=0;
+       int vlc_data=0;
+       int bit_cur;
+       int bit;
+       data+=4;
+       while (pos < packetlength) {
+               bit_cur=8;
+               while (bit_cur && bit_exp) {
+                       bit=((*data)>>(bit_cur-1))&1;
+                       if (!vlc_cod) {
+                               if (bit) {
+                                       vlc_size++;
+                               } else {
+                                       if (!vlc_size) {
+                                               decode_JangGu_integrate(se401, 0);
+                                       } else {
+                                               vlc_cod=2;
+                                               vlc_data=0;
+                                       }
+                               }
+                       } else {
+                               if (vlc_cod==2) {
+                                       if (!bit) vlc_data=-(1<<vlc_size)+1;
+                                       vlc_cod--;
+                               }
+                               vlc_size--;
+                               vlc_data+=bit<<vlc_size;
+                               if (!vlc_size) {
+                                       decode_JangGu_integrate(se401, vlc_data);
+                                       vlc_cod=0;
+                               }
+                       }
+                       bit_cur--;
+                       bit_exp--;
+               }
+               pos++;
+               data++;
+       }
+}
+
+static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+       unsigned char *data=buffer->data;
+       int len=buffer->length;
+       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
+       int datapos=0;
+
+       /* New image? */
+       if (!se401->frame[se401->curframe].curpix) {
+               se401->frame[se401->curframe].curlinepix=0;
+               se401->frame[se401->curframe].curline=
+                   se401->frame[se401->curframe].data+
+                   se401->cwidth*3-1;
+               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
+                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
+               se401->vlcdatapos=0;
+       }
+       while (datapos < len) {
+               size=1024-se401->vlcdatapos;
+               if (size+datapos > len)
+                       size=len-datapos;
+               memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
+               se401->vlcdatapos+=size;
+               packetlength=0;
+               if (se401->vlcdatapos >= 4) {
+                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
+                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
+                       frameinfo=se401->vlcdata[0]&0xc0;
+                       packetlength=((bit_exp+47)>>4)<<1;
+                       if (packetlength > 1024) {
+                               se401->vlcdatapos=0;
+                               datapos=len;
+                               packetlength=0;
+                               se401->error++;
+                               se401->frame[se401->curframe].curpix=0;
+                       }
+               }
+               if (packetlength && se401->vlcdatapos >= packetlength) {
+                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
+                       se401->frame[se401->curframe].curpix+=pix_exp*3;
+                       datapos+=size-(se401->vlcdatapos-packetlength);
+                       se401->vlcdatapos=0;
+                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
+                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
+                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
+                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
+                                               se401->framecount++;
+                                               se401->readcount++;
+                                       }
+                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+                                       }
+                               } else {
+                                       se401->error++;
+                               }
+                               se401->frame[se401->curframe].curpix=0;
+                               datapos=len;
+                       }
+               } else {
+                       datapos+=size;
+               }
+       }
+}
+
+static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+       unsigned char *data=buffer->data;
+       int len=buffer->length;
+       int offset=buffer->offset;
+       int datasize=se401->cwidth*se401->cheight;
+       struct se401_frame *frame=&se401->frame[se401->curframe];
+
+       unsigned char *framedata=frame->data, *curline, *nextline;
+       int width=se401->cwidth;
+       int blineoffset=0, bline;
+       int linelength=width*3, i;
+       
+
+       if (frame->curpix==0) {
+               if (frame->grabstate==FRAME_READY) {
+                       frame->grabstate=FRAME_GRABBING;
+               }
+               frame->curline=framedata+linelength;
+               frame->curlinepix=0;
+       }
+
+       if (offset!=frame->curpix) {
+               /* Regard frame as lost :( */
+               frame->curpix=0;
+               se401->error++;
+               return;
+       }
+
+       /* Check if we have to much data */
+       if (frame->curpix+len > datasize) {
+               len=datasize-frame->curpix;
+       }
+       if (se401->cheight%4)
+               blineoffset=1;
+       bline=frame->curpix/se401->cwidth+blineoffset;
+
+       curline=frame->curline;
+       nextline=curline+linelength;
+       if (nextline >= framedata+datasize*3)
+               nextline=curline;
+       while (len) {
+               if (frame->curlinepix>=width) {
+                       frame->curlinepix-=width;
+                       bline=frame->curpix/width+blineoffset;
+                       curline+=linelength*2;
+                       nextline+=linelength*2;
+                       if (curline >= framedata+datasize*3) {
+                               frame->curlinepix++;
+                               curline-=3;
+                               nextline-=3;
+                               len--;
+                               data++;
+                               frame->curpix++;
+                       }
+                       if (nextline >= framedata+datasize*3)
+                               nextline=curline;
+               }
+               if ((bline&1)) {
+                       if ((frame->curlinepix&1)) {
+                               *(curline+2)=*data;
+                               *(curline-1)=*data;
+                               *(nextline+2)=*data;
+                               *(nextline-1)=*data;
+                       } else {
+                               *(curline+1)=
+                                       (*(curline+1)+*data)/2;
+                               *(curline-2)=
+                                       (*(curline-2)+*data)/2;
+                               *(nextline+1)=*data;
+                               *(nextline-2)=*data;
+                       }
+               } else {
+                       if ((frame->curlinepix&1)) {
+                               *(curline+1)=
+                                       (*(curline+1)+*data)/2;
+                               *(curline-2)=
+                                       (*(curline-2)+*data)/2;
+                               *(nextline+1)=*data;
+                               *(nextline-2)=*data;
+                       } else {
+                               *curline=*data;
+                               *(curline-3)=*data;
+                               *nextline=*data;
+                               *(nextline-3)=*data;
+                       }
+               }
+               frame->curlinepix++;
+               curline-=3;
+               nextline-=3;
+               len--;
+               data++;
+               frame->curpix++;
+       }
+       frame->curline=curline;
+
+       if (frame->curpix>=datasize) {
+               /* Fix the top line */
+               framedata+=linelength;
+               for (i=0; i<linelength; i++) {
+                       *--framedata=*(framedata+linelength);
+               }
+               /* Fix the left side (green is already present) */
+               for (i=0; i<se401->cheight; i++) {
+                       *framedata=*(framedata+3);
+                       *(framedata+1)=*(framedata+4);
+                       *(framedata+2)=*(framedata+5);
+                       framedata+=linelength;
+               }
+               frame->curpix=0;
+               frame->grabstate=FRAME_DONE;
+               se401->framecount++;
+               se401->readcount++;
+               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+               }
+       }
+}
+
+static int se401_newframe(struct usb_se401 *se401, int framenr)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int errors=0;
+
+       while (se401->streaming &&
+           (se401->frame[framenr].grabstate==FRAME_READY ||
+            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
+               if(!se401->frame[framenr].curpix) {
+                       errors++;
+               }
+               wait_interruptible(
+                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
+                   &se401->wq,
+                   &wait
+               );
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+                       se401->nullpackets=0;
+                       info("to many null length packets, restarting capture");
+                       se401_stop_stream(se401);
+                       se401_start_stream(se401);                      
+               } else {
+                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
+                               se401->frame[framenr].grabstate=FRAME_ERROR;
+                               return -EIO;
+                       }
+                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
+                       if (se401->format==FMT_JANGGU) {
+                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
+                       } else {
+                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
+                       }
+                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+                       se401->scratch_use++;
+                       if (se401->scratch_use>=SE401_NUMSCRATCH)
+                               se401->scratch_use=0;
+                       if (errors > SE401_MAX_ERRORS) {
+                               errors=0;
+                               info("to much errors, restarting capture");
+                               se401_stop_stream(se401);
+                               se401_start_stream(se401);
+                       }
+               }
+       }
+       
+       if (se401->frame[framenr].grabstate==FRAME_DONE) 
+               if (se401->enhance)
+                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+       return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video4Linux
+ *
+ ***************************************************************************/
+
+
+static int se401_open(struct video_device *dev, int flags)
+{
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       int err = 0;
+
+       MOD_INC_USE_COUNT;
+       down(&se401->lock);
+
+       se401->fbuf=rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
+       if(!se401->fbuf) err=-ENOMEM;
+
+        if (err) {
+               MOD_DEC_USE_COUNT;
+               up(&se401->lock);
+               return err;
+       }
+       
+       se401->user=1;
+
+       up(&se401->lock);
+       
+       return 0;
+}
+
+static void se401_close(struct video_device *dev)
+{
+        struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       int i;
+
+       down(&se401->lock);
+
+       for (i=0; i<SE401_NUMFRAMES; i++)
+               se401->frame[i].grabstate=FRAME_UNUSED;
+       if (se401->streaming)
+               se401_stop_stream(se401);
+
+       rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
+       se401->user=0;
+       up(&se401->lock);
+
+        if (!se401->dev) {
+                video_unregister_device(&se401->vdev);
+               kfree(se401->width);
+               kfree(se401->height);
+                kfree(se401);
+                se401 = NULL;
+               info("device unregistered");
+       }
+
+        MOD_DEC_USE_COUNT;
+}
+
+static int se401_init_done(struct video_device *dev)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+        create_proc_se401_cam((struct usb_se401 *)dev);
+#endif
+
+        return 0;
+}
+
+static long se401_write(struct video_device *dev, const char *buf, unsigned long
+ count, int noblock)
+{
+        return -EINVAL;
+}
+
+static int se401_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+        struct usb_se401 *se401 = (struct usb_se401 *)vdev;
+
+        if (!se401->dev)
+                return -EIO;
+
+        switch (cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability b;
+               strcpy(b.name, se401->camera_name);
+               b.type = VID_TYPE_CAPTURE;
+               b.channels = 1;
+               b.audios = 0;
+               b.maxwidth = se401->width[se401->sizes-1];
+               b.maxheight = se401->height[se401->sizes-1];
+               b.minwidth = se401->width[0];
+               b.minheight = se401->height[0];
+
+               if (copy_to_user(arg, &b, sizeof(b)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case VIDIOCGCHAN:
+       {
+               struct video_channel v;
+
+               if (copy_from_user(&v, arg, sizeof(v)))
+                       return -EFAULT;
+               if (v.channel != 0)
+                       return -EINVAL;
+
+               v.flags = 0;
+               v.tuners = 0;
+               v.type = VIDEO_TYPE_CAMERA;
+               strcpy(v.name, "Camera");
+
+               if (copy_to_user(arg, &v, sizeof(v)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case VIDIOCSCHAN:
+       {
+               int v;
+
+               if (copy_from_user(&v, arg, sizeof(v)))
+                       return -EFAULT;
+
+               if (v != 0)
+                       return -EINVAL;
+
+               return 0;
+       }
+        case VIDIOCGPICT:
+        {
+               struct video_picture p;
+
+               se401_get_pict(se401, &p);
+
+               if (copy_to_user(arg, &p, sizeof(p)))
+                       return -EFAULT;
+               return 0;
+       }
+       case VIDIOCSPICT:
+       {
+               struct video_picture p;
+
+               if (copy_from_user(&p, arg, sizeof(p)))
+                       return -EFAULT;
+
+               if (se401_set_pict(se401, &p))
+                       return -EINVAL;
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window vw;
+
+               if (copy_from_user(&vw, arg, sizeof(vw)))
+                       return -EFAULT;
+               if (vw.flags)
+                       return -EINVAL;
+               if (vw.clipcount)
+                       return -EINVAL;
+               if (se401_set_size(se401, vw.width, vw.height))
+                       return -EINVAL;
+               
+               return 0;
+        }
+       case VIDIOCGWIN:
+       {
+               struct video_window vw;
+
+               vw.x = 0;               /* FIXME */
+               vw.y = 0;
+               vw.chromakey = 0;
+               vw.flags = 0;
+               vw.clipcount = 0;
+               vw.width = se401->cwidth;
+               vw.height = se401->cheight;
+
+               if (copy_to_user(arg, &vw, sizeof(vw)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf vm;
+               int i;
+
+               memset(&vm, 0, sizeof(vm));
+               vm.size = SE401_NUMFRAMES * se401->maxframesize;
+               vm.frames = SE401_NUMFRAMES;
+               for (i=0; i<SE401_NUMFRAMES; i++)
+                       vm.offsets[i] = se401->maxframesize * i;
+
+               if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+               return -EFAULT;
+
+               return 0;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap vm;
+
+               if (copy_from_user(&vm, arg, sizeof(vm)))
+               return -EFAULT;
+               if (vm.format != VIDEO_PALETTE_RGB24)
+                       return -EINVAL;
+               if (vm.frame >= SE401_NUMFRAMES)
+                       return -EINVAL;
+               if (se401->frame[vm.frame].grabstate != FRAME_UNUSED)
+                       return -EBUSY;
+
+               /* Is this according to the v4l spec??? */
+               if (se401_set_size(se401, vm.width, vm.height))
+                       return -EINVAL;
+               se401->frame[vm.frame].grabstate=FRAME_READY;
+
+               if (!se401->streaming)
+                       se401_start_stream(se401);
+
+               /* Set the picture properties */
+               if (se401->framecount==0)
+                       se401_send_pict(se401);
+               /* Calibrate the reset level after a few frames. */
+               if (se401->framecount%20==1)
+                       se401_auto_resetlevel(se401);
+
+               return 0;
+       }
+       case VIDIOCSYNC:
+       {
+               int frame, ret=0;
+
+               if (copy_from_user((void *)&frame, arg, sizeof(int)))
+                       return -EFAULT;
+
+               ret=se401_newframe(se401, frame);
+               se401->frame[frame].grabstate=FRAME_UNUSED;
+               return ret;
+       }
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer vb;
+
+               memset(&vb, 0, sizeof(vb));
+               vb.base = NULL; /* frame buffer not supported, not used */
+
+               if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case VIDIOCKEY:
+               return 0;
+       case VIDIOCCAPTURE:
+               return -EINVAL;
+       case VIDIOCSFBUF:
+               return -EINVAL;
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+               return -EINVAL;
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+               return -EINVAL;
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return -EINVAL;
+        default:
+                return -ENOIOCTLCMD;
+        } /* end switch */
+
+        return 0;
+}
+
+static long se401_read(struct video_device *dev, char *buf, unsigned long count,
+ int noblock)
+{
+       int realcount=count, ret=0;
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+
+
+       if (se401->dev == NULL)
+               return -EIO;
+       if (realcount > se401->cwidth*se401->cheight*3)
+               realcount=se401->cwidth*se401->cheight*3;
+
+       /* Shouldn't happen: */
+       if (se401->frame[0].grabstate==FRAME_GRABBING)
+               return -EBUSY;
+       se401->frame[0].grabstate=FRAME_READY;
+       se401->frame[1].grabstate=FRAME_UNUSED;
+       se401->curframe=0;
+
+       if (!se401->streaming)
+               se401_start_stream(se401);
+
+       /* Set the picture properties */
+       if (se401->framecount==0)
+               se401_send_pict(se401);
+       /* Calibrate the reset level after a few frames. */
+       if (se401->framecount%20==1)
+               se401_auto_resetlevel(se401);
+
+       ret=se401_newframe(se401, 0);
+
+       if (!ret) {
+               copy_to_user(buf, se401->frame[0].data, realcount);
+       } else {
+               realcount=ret;
+       }
+       se401->frame[0].grabstate=FRAME_UNUSED;
+
+       return realcount;
+}
+
+static int se401_mmap(struct video_device *dev, const char *adr,
+        unsigned long size)
+{
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       unsigned long start = (unsigned long)adr;
+       unsigned long page, pos;
+
+       down(&se401->lock);
+       
+       if (se401->dev == NULL) {
+               up(&se401->lock);
+               return -EIO;
+       }
+       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+               up(&se401->lock);
+               return -EINVAL;
+       }
+       pos = (unsigned long)se401->fbuf;
+       while (size > 0) {
+               page = kvirt_to_pa(pos);
+               if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       up(&se401->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       up(&se401->lock);
+
+        return 0;
+}
+
+static struct video_device se401_template = {
+        name:           "se401 USB camera",
+        type:           VID_TYPE_CAPTURE,
+        hardware:       VID_HARDWARE_SE401,
+        open:           se401_open,
+        close:          se401_close,
+        read:           se401_read,
+        write:          se401_write,
+        ioctl:          se401_ioctl,
+        mmap:           se401_mmap,
+        initialize:     se401_init_done,
+};
+
+
+
+/***************************/
+static int se401_init(struct usb_se401 *se401)
+{
+        int i=0, rc;
+        unsigned char cp[0x40];
+       char temp[200];
+
+       /* led on */
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+       /* get camera descriptor */
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
+       if (cp[1]!=0x41) {
+               err("Wrong descriptor type");
+               return 1;
+       }
+       sprintf (temp, "ExtraFeatures: %d", cp[3]);
+
+       se401->sizes=cp[4]+cp[5]*256;
+       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       for (i=0; i<se401->sizes; i++) {
+                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
+                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+       }
+       sprintf (temp, "%s Sizes:", temp);
+       for (i=0; i<se401->sizes; i++) {
+               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+       }
+       info("%s", temp);
+       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+       se401->cwidth=cp[0]+cp[1]*256;
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+       se401->cheight=cp[0]+cp[1]*256;
+
+       if (!cp[2] && SE401_FORMAT_BAYER) {
+               err("Bayer format not supported!");
+               return 1;
+       }
+       /* set output mode (BAYER) */
+        se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+       se401->brightness=cp[0]+cp[1]*256;
+       /* some default values */
+       se401->resetlevel=0x2d;
+       se401->rgain=0x20;
+       se401->ggain=0x20;
+       se401->bgain=0x20;
+       se401_set_exposure(se401, 20000);
+       se401->palette=VIDEO_PALETTE_RGB24;
+       se401->enhance=1;
+       se401->dropped=0;
+       se401->error=0;
+       se401->framecount=0;
+       se401->readcount=0;
+
+       /* Start interrupt transfers for snapshot button */
+       se401->inturb=usb_alloc_urb(0);
+       if (!se401->inturb) {
+               info("Allocation of inturb failed");
+               return 1;
+       }
+       FILL_INT_URB(se401->inturb, se401->dev,
+           usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
+           &se401->button, sizeof(se401->button),
+           se401_button_irq,
+           se401,
+           HZ/10
+       );
+       if (usb_submit_urb(se401->inturb)) {
+               info("int urb burned down");
+               return 1;
+       }
+       
+        /* Flash the led */
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+
+        return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
+static void* se401_probe(struct usb_device *dev, unsigned int ifnum)
+#else
+static void* __devinit se401_probe(struct usb_device *dev, unsigned int ifnum,
+       const struct usb_device_id *id)
+#endif
+{
+        struct usb_interface_descriptor *interface;
+        struct usb_se401 *se401;
+        char *camera_name=NULL;
+
+        /* We don't handle multi-config cameras */
+        if (dev->descriptor.bNumConfigurations != 1)
+                return NULL;
+
+        interface = &dev->actconfig->interface[ifnum].altsetting[0];
+
+        /* Is it an se401? */
+        if (dev->descriptor.idVendor == 0x03e8 &&
+            dev->descriptor.idProduct == 0x0004) {
+                camera_name="Endpoints/Aox SE401";
+        } else if (dev->descriptor.idVendor == 0x0471 &&
+            dev->descriptor.idProduct == 0x030b) {
+                camera_name="Philips PCVC665K";
+        } else if (dev->descriptor.idVendor == 0x047d &&
+           dev->descriptor.idProduct == 0x5001) {
+               camera_name="Kensington VideoCAM 67014";
+        } else if (dev->descriptor.idVendor == 0x047d &&
+           dev->descriptor.idProduct == 0x5002) {
+               camera_name="Kensington VideoCAM 6701(5/7)";
+        } else if (dev->descriptor.idVendor == 0x047d &&
+           dev->descriptor.idProduct == 0x5003) {
+               camera_name="Kensington VideoCAM 67016";
+       } else
+               return NULL;
+
+        /* Checking vendor/product should be enough, but what the hell */
+        if (interface->bInterfaceClass != 0x00)
+                return NULL;
+        if (interface->bInterfaceSubClass != 0x00)
+                return NULL;
+
+        /* We found one */
+        info("SE401 camera found: %s", camera_name);
+
+        if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+                err("couldn't kmalloc se401 struct");
+                return NULL;
+        }
+
+        memset(se401, 0, sizeof(*se401));
+
+        se401->dev = dev;
+        se401->iface = interface->bInterfaceNumber;
+        se401->camera_name = camera_name;
+
+       info("firmware version: %02x", dev->descriptor.bcdDevice & 255);
+
+        if (se401_init(se401))
+               return NULL;
+       memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
+       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               err("video_register_device failed");
+               return NULL;
+       }
+       info("registered new video device: video%d", se401->vdev.minor);
+
+       init_waitqueue_head(&se401->wq);
+       init_MUTEX(&se401->lock);
+
+        return se401;
+}
+
+static void se401_disconnect(struct usb_device *dev, void *ptr)
+{
+       int i;
+       struct usb_se401 *se401 = (struct usb_se401 *) ptr;
+
+       /* We don't want people trying to open up the device */
+       if (!se401->user)
+              video_unregister_device(&se401->vdev);
+
+        usb_driver_release_interface(&se401_driver,
+                &se401->dev->actconfig->interface[se401->iface]);
+
+        se401->dev = NULL;
+        se401->frame[0].grabstate = FRAME_ERROR;
+        se401->frame[1].grabstate = FRAME_ERROR;
+
+       se401->streaming = 0;
+
+       if (waitqueue_active(&se401->wq))
+                wake_up_interruptible(&se401->wq);
+
+       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+               se401->urb[i]->next = NULL;
+               usb_unlink_urb(se401->urb[i]);
+               usb_free_urb(se401->urb[i]);
+               se401->urb[i] = NULL;
+               kfree(se401->sbuf[i].data);
+       }
+       for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
+               kfree(se401->scratch[i].data);
+       }
+       if (se401->inturb) {
+               usb_unlink_urb(se401->inturb);
+               usb_free_urb(se401->inturb);
+       }
+        info("%s disconnected", se401->camera_name);
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+       destroy_proc_se401_cam(se401);
+#endif
+
+        /* Free the memory */
+        if (!se401->user) {
+               kfree(se401->width);
+               kfree(se401->height);
+                kfree(se401);
+                se401 = NULL;
+        }
+}
+
+
+static struct usb_driver se401_driver = {
+        name:          "se401",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
+        id_table:      device_table,
+#endif
+       probe:          se401_probe,
+        disconnect:    se401_disconnect
+};
+
+
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init usb_se401_init(void)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+       proc_se401_create();
+#endif
+
+       info("SE401 usb camera driver version %s registering", version);
+       if (flickerless)
+               if (flickerless!=50 && flickerless!=60) {
+                       info("Invallid flickerless value, use 0, 50 or 60.");
+                       return -1;
+       }
+       if (usb_register(&se401_driver) < 0)
+               return -1;
+       return 0;
+}
+
+static void __exit usb_se401_exit(void)
+{
+       usb_deregister(&se401_driver);
+       info("SE401 driver deregistered");
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+       proc_se401_destroy();
+#endif
+}
+
+module_init(usb_se401_init);
+module_exit(usb_se401_exit);
diff --git a/drivers/usb/se401.h b/drivers/usb/se401.h
new file mode 100644 (file)
index 0000000..97dae91
--- /dev/null
@@ -0,0 +1,234 @@
+
+#ifndef __LINUX_se401_H
+#define __LINUX_se401_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+#define se401_DEBUG    /* Turn on debug messages */
+
+#ifdef se401_DEBUG
+#  define PDEBUG(level, fmt, args...) \
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+#else
+#  define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* An almost drop-in replacement for sleep_on_interruptible */
+#define wait_interruptible(test, queue, wait) \
+{ \
+       add_wait_queue(queue, wait); \
+       set_current_state(TASK_INTERRUPTIBLE); \
+       if (test) \
+               schedule(); \
+       remove_wait_queue(queue, wait); \
+       set_current_state(TASK_RUNNING); \
+       if (signal_pending(current)) \
+               break; \
+}
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
+#define SE401_REQ_CAPTURE_FRAME                        0x43
+#define SE401_REQ_GET_BRT                      0x44
+#define SE401_REQ_SET_BRT                      0x45
+#define SE401_REQ_GET_WIDTH                    0x4c
+#define SE401_REQ_SET_WIDTH                    0x4d
+#define SE401_REQ_GET_HEIGHT                   0x4e
+#define SE401_REQ_SET_HEIGHT                   0x4f
+#define SE401_REQ_GET_OUTPUT_MODE              0x50
+#define SE401_REQ_SET_OUTPUT_MODE              0x51
+#define SE401_REQ_GET_EXT_FEATURE              0x52
+#define SE401_REQ_SET_EXT_FEATURE              0x53
+#define SE401_REQ_CAMERA_POWER                 0x56
+#define SE401_REQ_LED_CONTROL                  0x57
+#define SE401_REQ_BIOS                         0xff
+
+#define SE401_BIOS_READ                                0x07
+
+#define SE401_FORMAT_BAYER     0x40
+
+/* Hyundai hv7131b registers
+   7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A              0x00
+#define HV7131_REG_MODE_B              0x01
+#define HV7131_REG_MODE_C              0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU                0x10
+#define HV7131_REG_FRSL                0x11
+#define HV7131_REG_FCSU                0x12
+#define HV7131_REG_FCSL                0x13
+#define HV7131_REG_FWHU                0x14
+#define HV7131_REG_FWHL                0x15
+#define HV7131_REG_FWWU                0x16
+#define HV7131_REG_FWWL                0x17
+/* Timing registers: */
+#define HV7131_REG_THBU                0x20
+#define HV7131_REG_THBL                0x21
+#define HV7131_REG_TVBU                0x22
+#define HV7131_REG_TVBL                0x23
+#define HV7131_REG_TITU                0x25
+#define HV7131_REG_TITM                0x26
+#define HV7131_REG_TITL                0x27
+#define HV7131_REG_TMCD                0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV                0x30
+#define HV7131_REG_ARCG                0x31
+#define HV7131_REG_AGCG                0x32
+#define HV7131_REG_ABCG                0x33
+#define HV7131_REG_APBV                0x34
+#define HV7131_REG_ASLP                0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR                0x50
+#define HV7131_REG_OFSG                0x51
+#define HV7131_REG_OFSB                0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH    0x57
+#define HV7131_REG_LOREFNOL    0x58
+#define HV7131_REG_HIREFNOH    0x59
+#define HV7131_REG_HIREFNOL    0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE    0x2000
+
+
+/* size of usb transfers */
+#define SE401_PACKETSIZE       4096
+/* number of queued bulk transfers to use, should be about 8 */
+#define SE401_NUMSBUF          1
+/* read the usb specs for this one :) */
+#define SE401_VIDEO_ENDPOINT   1
+#define SE401_BUTTON_ENDPOINT  2
+/* number of frames supported by the v4l part */
+#define SE401_NUMFRAMES                2
+/* scratch buffers for passing data to the decoders */
+#define SE401_NUMSCRATCH       32
+/* maximum amount of data in a JangGu packet */
+#define SE401_VLCDATALEN       1024
+/* number of nul sized packets to receive before kicking the camera */
+#define SE401_MAX_NULLPACKETS  4000
+/* number of decoding errors before kicking the camera */
+#define SE401_MAX_ERRORS       200
+
+struct usb_device;
+
+struct se401_sbuf {
+       unsigned char *data;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+enum {
+       FMT_BAYER,
+       FMT_JANGGU,
+};
+
+enum {
+       BUFFER_UNUSED,
+       BUFFER_READY,
+       BUFFER_BUSY,
+       BUFFER_DONE,
+};
+
+struct se401_scratch {
+       unsigned char *data;
+       volatile int state;
+       int offset;
+       int length;
+};
+
+struct se401_frame {
+       unsigned char *data;            /* Frame buffer */
+
+       volatile int grabstate; /* State of grabbing */
+
+       unsigned char *curline;
+       int curlinepix;
+       int curpix;
+};
+
+struct usb_se401 {
+       struct video_device vdev;
+
+       /* Device structure */
+       struct usb_device *dev;
+
+       unsigned char iface;
+
+       char *camera_name;
+
+       int change;
+       int brightness;
+       int hue;
+       int rgain;
+       int ggain;
+       int bgain;
+       int expose_h;
+       int expose_m;
+       int expose_l;
+       int resetlevel;
+       
+       int enhance;
+
+       int format;
+       int sizes;
+       int *width;
+       int *height;
+       int cwidth;             /* current width */
+       int cheight;            /* current height */
+       int palette;
+       int maxframesize;
+       int cframesize;         /* current framesize */
+
+       struct semaphore lock;
+       int user;               /* user count for exclusive use */
+
+       int streaming;          /* Are we streaming video? */
+
+       char *fbuf;             /* Videodev buffer area */
+
+       urb_t *urb[SE401_NUMSBUF];
+       urb_t *inturb;
+       
+       int button;
+       int buttonpressed;
+
+       int curframe;           /* Current receiving frame */
+       struct se401_frame frame[SE401_NUMFRAMES];      
+       int readcount;
+       int framecount;
+       int error;
+       int dropped;
+
+       int scratch_next;
+       int scratch_use;
+       int scratch_overflow;
+       struct se401_scratch scratch[SE401_NUMSCRATCH];
+
+       /* Decoder specific data: */
+       unsigned char vlcdata[SE401_VLCDATALEN];
+       int vlcdatapos;
+       int bayeroffset;
+
+       struct se401_sbuf sbuf[SE401_NUMSBUF];
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       /* proc interface */
+       struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
+
+       int nullpackets;
+};
+
+
+#endif
+
index 2b91d038e3aefb8f70f86895262bb9832475b584..c4306e9115a984fb55d93f2f7b524020108df189 100644 (file)
@@ -28,6 +28,8 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then
      bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
   fi
   dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 fi
 
index 36fc63958f18dbdf293164db6d9f6fa56f2ab358..cb4256b635f67ba2dddc22fc4d4c76d4d01bc090 100644 (file)
@@ -18,6 +18,8 @@ obj-$(CONFIG_USB_SERIAL_BELKIN)                       += belkin_sa.o
 obj-$(CONFIG_USB_SERIAL_EMPEG)                 += empeg.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)              += mct_u232.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT)              += io_edgeport.o
+obj-$(CONFIG_USB_SERIAL_PL2303)                        += pl2303.o
+obj-$(CONFIG_USB_SERIAL_CYBERJACK)             += cyberjack.o
  
 # Objects that export symbols.
 export-objs    := usbserial.o
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
new file mode 100644 (file)
index 0000000..f20af60
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ *  REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver
+ *
+ *  Copyright (C) 2001  REINER SCT
+ *  Author: Matthias Bruestle
+ *
+ *  Contact: linux-usb@sii.li (see MAINTAINERS)
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *
+ *  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.
+ *
+ *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
+ *  patience.
+ *
+ *  In case of problems, please write to the contact e-mail address
+ *  mentioned above.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       static int debug = 1;
+#else
+       static int debug;
+#endif
+
+#include "usb-serial.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Matthias Bruestle"
+#define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver"
+
+
+#define CYBERJACK_VENDOR_ID    0x0C4B
+#define CYBERJACK_PRODUCT_ID   0x0100
+
+/* Function prototypes */
+static int cyberjack_startup (struct usb_serial *serial);
+static void cyberjack_shutdown (struct usb_serial *serial);
+static int  cyberjack_open (struct usb_serial_port *port, struct file *filp);
+static void cyberjack_close (struct usb_serial_port *port, struct file *filp);
+static int cyberjack_write (struct usb_serial_port *port, int from_user,
+       const unsigned char *buf, int count);
+static void cyberjack_read_int_callback( struct urb *urb );
+static void cyberjack_read_bulk_callback (struct urb *urb);
+static void cyberjack_write_bulk_callback (struct urb *urb);
+
+static __devinitdata struct usb_device_id id_table [] = {
+       { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
+       { }                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type cyberjack_device = {
+       name:                   "Reiner SCT Cyberjack USB card reader",
+       id_table:               id_table,
+       needs_interrupt_in:     MUST_HAVE,
+       needs_bulk_in:          MUST_HAVE,
+       needs_bulk_out:         MUST_HAVE,
+       num_interrupt_in:       1,
+       num_bulk_in:            1,
+       num_bulk_out:           1,
+       num_ports:              1,
+       startup:                cyberjack_startup,
+       shutdown:               cyberjack_shutdown,
+       open:                   cyberjack_open,
+       close:                  cyberjack_close,
+       write:                  cyberjack_write,
+       read_int_callback:      cyberjack_read_int_callback,
+       read_bulk_callback:     cyberjack_read_bulk_callback,
+       write_bulk_callback:    cyberjack_write_bulk_callback,
+};
+
+struct cyberjack_private {
+       short   rdtodo;         /* Bytes still to read */
+       unsigned char   wrbuf[5*64];    /* Buffer for collecting data to write */
+       short   wrfilled;       /* Overall data size we already got */
+       short   wrsent;         /* Data akready sent */
+};
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int cyberjack_startup (struct usb_serial *serial)
+{
+       struct cyberjack_private *priv;
+
+       dbg (__FUNCTION__);
+
+       /* allocate the private data structure */
+       serial->port->private = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
+       if (!serial->port->private)
+               return (-1); /* error */
+
+       /* set initial values */
+       priv = (struct cyberjack_private *)serial->port->private;
+       priv->rdtodo = 0;
+       priv->wrfilled = 0;
+       priv->wrsent = 0;
+
+       init_waitqueue_head(&serial->port->write_wait);
+
+       return( 0 );
+}
+
+static void cyberjack_shutdown (struct usb_serial *serial)
+{
+       int i;
+       
+       dbg (__FUNCTION__);
+
+       /* stop reads and writes on all ports */
+       for (i=0; i < serial->num_ports; ++i) {
+               while (serial->port[i].open_count > 0) {
+                       cyberjack_close (&serial->port[i], NULL);
+               }
+               /* My special items, the standard routines free my urbs */
+               if (serial->port[i].private)
+                       kfree(serial->port[i].private);
+       }
+}
+       
+static int  cyberjack_open (struct usb_serial_port *port, struct file *filp)
+{
+       struct cyberjack_private *priv;
+       int result = 0;
+
+       if (port_paranoia_check (port, __FUNCTION__))
+               return -ENODEV;
+
+       MOD_INC_USE_COUNT;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       down (&port->sem);
+
+       ++port->open_count;
+
+       if (!port->active) {
+               port->active = 1;
+               /* force low_latency on so that our tty_push actually forces
+                * the data through, otherwise it is scheduled, and with high
+                * data rates (like with OHCI) data can get lost.
+                */
+               port->tty->low_latency = 1;
+
+               priv = (struct cyberjack_private *)port->private;
+               priv->rdtodo = 0;
+               priv->wrfilled = 0;
+               priv->wrsent = 0;
+
+               /* shutdown any bulk reads that might be going on */
+               usb_unlink_urb (port->write_urb);
+               usb_unlink_urb (port->read_urb);
+               usb_unlink_urb (port->interrupt_in_urb);
+
+               port->interrupt_in_urb->dev = port->serial->dev;
+               result = usb_submit_urb(port->interrupt_in_urb);
+               if (result)
+                       err(" usb_submit_urb(read int) failed");
+               dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
+       }
+
+       up (&port->sem);
+
+       return result;
+}
+
+static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
+{
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       down (&port->sem);
+
+       --port->open_count;
+
+       if (port->open_count <= 0) {
+               /* shutdown any bulk reads that might be going on */
+               usb_unlink_urb (port->write_urb);
+               usb_unlink_urb (port->read_urb);
+               usb_unlink_urb (port->interrupt_in_urb);
+
+               port->active = 0;
+               port->open_count = 0;
+       }
+
+       up (&port->sem);
+       MOD_DEC_USE_COUNT;
+}
+
+static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+       struct usb_serial *serial = port->serial;
+       struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+       int result;
+       int wrexpected;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       dbg(__FUNCTION__ " - from_user %d", from_user);
+
+       if (count == 0) {
+               dbg(__FUNCTION__ " - write request of 0 bytes");
+               return (0);
+       }
+
+       if (port->write_urb->status == -EINPROGRESS) {
+               dbg (__FUNCTION__ " - already writing");
+               return (0);
+       }
+
+       down (&port->sem);
+
+       if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
+               /* To much data  for buffer. Reset buffer. */
+               priv->wrfilled=0;
+               return (0);
+       }
+
+       /* Copy data */
+       if (from_user) {
+               copy_from_user(priv->wrbuf+priv->wrfilled, buf, count);
+       } else {
+               memcpy (priv->wrbuf+priv->wrfilled, buf, count);
+       }  
+       usb_serial_debug_data (__FILE__, __FUNCTION__, count,
+               priv->wrbuf+priv->wrfilled);
+       priv->wrfilled += count;
+
+       if( priv->wrfilled >= 3 ) {
+               wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
+               dbg(__FUNCTION__ " - expected data: %d", wrexpected);
+       } else {
+               wrexpected = sizeof(priv->wrbuf);
+       }
+
+       if( priv->wrfilled >= wrexpected ) {
+               /* We have enough data to begin transmission */
+               int length;
+
+               dbg(__FUNCTION__ " - transmitting data (frame 1)");
+               length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected;
+
+               memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length );
+               priv->wrsent=length;
+
+               /* set up our urb */
+               FILL_BULK_URB(port->write_urb, serial->dev, 
+                             usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+                             port->write_urb->transfer_buffer, length,
+                             ((serial->type->write_bulk_callback) ? 
+                              serial->type->write_bulk_callback : 
+                              cyberjack_write_bulk_callback), 
+                             port);
+
+               /* send the data out the bulk port */
+               result = usb_submit_urb(port->write_urb);
+               if (result) {
+                       err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+                       /* Throw away data. No better idea what to do with it. */
+                       priv->wrfilled=0;
+                       priv->wrsent=0;
+                       up (&port->sem);
+                       return 0;
+               }
+
+               dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
+               dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+
+               if( priv->wrsent>=priv->wrfilled ) {
+                       dbg(__FUNCTION__ " - buffer cleaned");
+                       memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
+                       priv->wrfilled=0;
+                       priv->wrsent=0;
+               }
+       }
+
+       up (&port->sem);
+       return (count);
+} 
+
+static void cyberjack_read_int_callback( struct urb *urb )
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+       struct usb_serial *serial;
+       unsigned char *data = urb->transfer_buffer;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       /* the urb might have been killed. */
+       if (urb->status)
+               return;
+
+       if (port_paranoia_check (port, "cyberjack_read_interrupt")) return;
+
+       serial = port->serial;
+       if (serial_paranoia_check (serial, "cyberjack_read_interrupt")) return;
+
+       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+       /* React only to interrupts signaling a bulk_in transfer */
+       if( (urb->actual_length==4) && (data[0]==0x01) ) {
+               short old_rdtodo = priv->rdtodo;
+               int result;
+
+               /* This is a announcement of comming bulk_ins. */
+               unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
+
+               if( (size>259) || (size==0) ) {
+                       dbg( "Bad announced bulk_in data length: %d", size );
+                       /* Dunno what is most reliable to do here. */
+                       /* return; */
+               }
+
+               if( (old_rdtodo+size)<(old_rdtodo) ) {
+                       dbg( "To many bulk_in urbs to do." );
+                       return;
+               }
+
+               /* "+=" is probably more fault tollerant than "=" */
+               priv->rdtodo += size;
+
+               dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+
+               if( !old_rdtodo ) {
+                       port->read_urb->dev = port->serial->dev;
+                       result = usb_submit_urb(port->read_urb);
+                       if( result )
+                               err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+                       dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+               }
+       }
+}
+
+static void cyberjack_read_bulk_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+       int i;
+       int result;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+
+       if (urb->status) {
+               usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+               dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+               return;
+       }
+
+       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+       tty = port->tty;
+       if (urb->actual_length) {
+               for (i = 0; i < urb->actual_length ; ++i) {
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       /* this doesn't actually push the data through unless tty->low_latency is set */
+                       tty_insert_flip_char(tty, data[i], 0);
+               }
+               tty_flip_buffer_push(tty);
+       }
+
+       /* Reduce urbs to do by one. */
+       priv->rdtodo-=urb->actual_length;
+       /* Just to be sure */
+       if( priv->rdtodo<0 ) priv->rdtodo=0;
+
+       dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+
+       /* Continue to read if we have still urbs to do. */
+       if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
+               port->read_urb->dev = port->serial->dev;
+               result = usb_submit_urb(port->read_urb);
+               if (result)
+                       err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+               dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+       }
+}
+
+static void cyberjack_write_bulk_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+
+       if (urb->status) {
+               dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+               return;
+       }
+
+       /* only do something if we have more data to send */
+       if( priv->wrfilled ) {
+               int length, blksize, result;
+
+               if (port->write_urb->status == -EINPROGRESS) {
+                       dbg (__FUNCTION__ " - already writing");
+                       return;
+               }
+
+               down (&port->sem);
+
+               dbg(__FUNCTION__ " - transmitting data (frame n)");
+
+               length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
+                       port->bulk_out_size : (priv->wrfilled - priv->wrsent);
+
+               memcpy (port->write_urb->transfer_buffer, priv->wrbuf + priv->wrsent,
+                       length );
+               priv->wrsent+=length;
+
+               /* set up our urb */
+               FILL_BULK_URB(port->write_urb, serial->dev, 
+                             usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+                             port->write_urb->transfer_buffer, length,
+                             ((serial->type->write_bulk_callback) ? 
+                              serial->type->write_bulk_callback : 
+                              cyberjack_write_bulk_callback), 
+                             port);
+
+               /* send the data out the bulk port */
+               result = usb_submit_urb(port->write_urb);
+               if (result) {
+                       err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+                       /* Throw away data. No better idea what to do with it. */
+                       priv->wrfilled=0;
+                       priv->wrsent=0;
+                       up (&port->sem);
+                       queue_task(&port->tqueue, &tq_immediate);
+                       mark_bh(IMMEDIATE_BH);
+                       return;
+               }
+
+               dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
+               dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+
+               blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
+
+               if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) {
+                       dbg(__FUNCTION__ " - buffer cleaned");
+                       memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
+                       priv->wrfilled=0;
+                       priv->wrsent=0;
+               }
+
+               up (&port->sem);
+               queue_task(&port->tqueue, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+               return;
+       }
+
+       queue_task(&port->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+       
+       return;
+}
+
+static int __init cyberjack_init (void)
+{
+       usb_serial_register (&cyberjack_device);
+
+       info(DRIVER_VERSION " " DRIVER_AUTHOR);
+       info(DRIVER_DESC);
+
+       return 0;
+}
+
+static void __exit cyberjack_exit (void)
+{
+       usb_serial_deregister (&cyberjack_device);
+}
+
+module_init(cyberjack_init);
+module_exit(cyberjack_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
new file mode 100644 (file)
index 0000000..e0b9562
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+ * Prolific PL2303 USB to serial adaptor driver
+ *
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * Original driver for 2.2.x by anonymous
+ *
+ *     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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * 2001_Jun_06 gkh
+ *     finished porting to 2.4 format.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       static int debug = 1;
+#else
+       static int debug;
+#endif
+
+#include "usb-serial.h"
+#include "pl2303.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
+
+
+#ifndef MIN
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+#endif
+
+
+#define        PL2303_LOCK(port,flags)                                 \
+               do {                                            \
+               spin_lock_irqsave(&((struct pl2303_private *)(port->private))->lock, flags);    \
+               } while (0)
+
+#define        PL2303_UNLOCK(port,flags)                               \
+               do {                                            \
+               spin_unlock_irqrestore(&((struct pl2303_private *)(port->private))->lock, flags);       \
+               } while (0)
+
+
+
+static __devinitdata struct usb_device_id id_table [] = {
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
+       { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+       { }                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct pl2303_private {
+       spinlock_t      lock;
+       unsigned char   *xmit_buf;
+       int             xmit_head;
+       int             xmit_tail;
+       int             xmit_cnt;
+};
+
+/* function prototypes for a PL2303 serial converter */
+static int pl2303_startup (struct usb_serial *serial);
+static int pl2303_open (struct usb_serial_port *port, struct file *filp);
+static void pl2303_close (struct usb_serial_port *port, struct file *filp);
+static void pl2303_set_termios (struct usb_serial_port *port,
+                               struct termios *old);
+static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+                        unsigned int cmd, unsigned long arg);
+static void pl2303_throttle (struct usb_serial_port *port);
+static void pl2303_unthrottle (struct usb_serial_port *port);
+static void pl2303_read_int_callback (struct urb *urb);
+static void pl2303_read_bulk_callback (struct urb *urb);
+static void pl2303_write_bulk_callback (struct urb *urb);
+static int pl2303_write (struct usb_serial_port *port, int from_user,
+                        const unsigned char *buf, int count);
+static int pl2303_write_room(struct usb_serial_port *port);
+static int pl2303_chars_in_buffer(struct usb_serial_port *port);
+static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
+static void start_xmit (struct usb_serial_port *port);
+
+
+/* All of the device info needed for the PL2303 SIO serial converter */
+static struct usb_serial_device_type pl2303_device = {
+       name:                   "PL-2303",
+       id_table:               id_table,
+       needs_interrupt_in:     DONT_CARE,              /* this device must have an interrupt in endpoint */
+       needs_bulk_in:          MUST_HAVE,              /* this device must have a bulk in endpoint */
+       needs_bulk_out:         MUST_HAVE,              /* this device must have a bulk out endpoint */
+       num_interrupt_in:       NUM_DONT_CARE,
+       num_bulk_in:            1,
+       num_bulk_out:           1,
+       num_ports:              1,
+       open:                   pl2303_open,
+       close:                  pl2303_close,
+       throttle:               pl2303_throttle,
+       unthrottle:             pl2303_unthrottle,
+       write:                  pl2303_write,
+       ioctl:                  pl2303_ioctl,
+       write_room:             pl2303_write_room,
+       chars_in_buffer:        pl2303_chars_in_buffer,
+       break_ctl:              pl2303_break_ctl,
+       set_termios:            pl2303_set_termios,
+       read_bulk_callback:     pl2303_read_bulk_callback,
+       read_int_callback:      pl2303_read_int_callback,
+       write_bulk_callback:    pl2303_write_bulk_callback,
+       startup:                pl2303_startup,
+};
+
+
+#define WDR_TIMEOUT (HZ * 5 )   /* default urb timeout */
+
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX (tmp_buf_sem);
+
+
+
+static int
+pl2303_write (struct usb_serial_port *port, int from_user,
+             const unsigned char *buf, int count)
+{                              /* pl2303_write */
+       struct pl2303_private *info = (struct pl2303_private *)port->private;
+       unsigned long flags;
+       int c,ret=0;
+       struct tty_struct *tty=port->tty;
+
+       dbg ("pl2303_write port %d, %d bytes", port->number, count);
+
+       if (!info) {
+               return -ENODEV;
+       }
+
+       if (!tty || !info->xmit_buf || !tmp_buf) {
+               return 0;
+       }
+
+
+       PL2303_LOCK(port,flags);
+
+
+       if (from_user) {
+               down(&tmp_buf_sem);
+               while (1) {
+                       c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                          SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0)
+                               break;
+
+                       c -= copy_from_user(tmp_buf, buf, c);
+                       if (!c) {
+                               if (!ret) {
+                                       ret = -EFAULT;
+                               }
+                               break;
+                       }
+                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                      SERIAL_XMIT_SIZE - info->xmit_head));
+                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+                       info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
+                       info->xmit_cnt += c;
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               up(&tmp_buf_sem);
+       } else {
+               while (1) {
+                       c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, 
+                                          SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0) {
+                               break;
+                       }
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+                       info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+                       info->xmit_cnt += c;
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+       }
+       PL2303_UNLOCK(port, flags);
+
+       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+               start_xmit(port);
+       }
+       return ret;
+}
+
+static int pl2303_write_room(struct usb_serial_port *port)
+{
+       struct pl2303_private *info = (struct pl2303_private *)port->private;
+       int     ret;
+
+       if (!info)
+               return 0;
+
+       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+       if (ret < 0)
+               ret = 0;
+       return ret;
+}
+
+static int pl2303_chars_in_buffer(struct usb_serial_port *port)
+{
+       struct pl2303_private *info = (struct pl2303_private *)port->private;
+
+       if (!info)
+               return 0;
+
+       return info->xmit_cnt;
+}
+
+static void pl2303_throttle(struct usb_serial_port *port)
+{
+#if 0
+       //struct usb_serial *serial = port->serial;
+       struct tty_struct *tty=port->tty;
+       unsigned long flags;
+
+
+       char    buf[64];
+
+       dbg("throttle %s: %d....", tty_name(tty, buf),
+           tty->ldisc.chars_in_buffer(tty));
+
+//FIXME FIXME FIXME    
+       if (I_IXOFF(tty))
+               rs_send_xchar(tty, STOP_CHAR(tty));
+
+       PL2303_LOCK(port,flags);
+       //Should remove read request if one is present
+       PL2303_UNLOCK(port,flags);
+#endif
+}
+
+static void pl2303_unthrottle(struct usb_serial_port *port)
+{
+#if 0
+       //struct usb_serial *serial = port->serial;
+       struct tty_struct *tty=port->tty;
+       unsigned long flags;
+
+
+       char    buf[64];
+
+       dbg("unthrottle %s: %d....", tty_name(tty, buf),
+           tty->ldisc.chars_in_buffer(tty));
+
+       //FIXME FIXME FIXME FIXME FIXME
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_send_xchar(tty, START_CHAR(tty));
+       }
+
+       PL2303_LOCK(port,flags);
+       //Should add read request if one is not present
+       PL2303_UNLOCK(fport,flags);
+#endif
+}
+
+
+static void
+pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{                              /* pl2303_set_termios */
+       struct usb_serial *serial = port->serial;
+       unsigned int cflag = port->tty->termios->c_cflag;
+       unsigned char buf[7] = { 0, 0, 0, 0, 0, 0, 0};
+       int baud;
+       int i;
+
+
+       dbg ("pl2303_set_termios port %d", port->number);
+
+
+       i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+                            0x21, 0xa1, 0, 0, buf, 7, 100);
+
+       dbg ("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
+            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+
+       i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+                            1, 0x40, 0, 1, NULL, 0, 100);
+
+       dbg ("0x40:1:0:1  %d", i);
+
+
+
+       if (cflag & CSIZE) {
+               switch (cflag & CSIZE) {
+                       case CS6:
+                               buf[6] = 6;
+                               dbg ("Setting CS6");
+                               break;
+                       case CS7:
+                               buf[6] = 7;
+                               dbg ("Setting CS7");
+                               break;
+                       case CS8:
+                               buf[6] = 8;
+                               dbg ("Setting CS8");
+                               break;
+                       default:
+                               err ("CSIZE was set but not CS6-CS8");
+               }
+       }
+
+       baud = 0;
+       switch (cflag & CBAUD) {
+               case B0:
+                       err ("Can't do B0 yet");  //FIXME
+                       break;
+               case B300:
+                       baud = 300;
+                       break;
+               case B600:
+                       baud = 600;
+                       break;
+               case B1200:
+                       baud = 1200;
+                       break;
+               case B2400:
+                       baud = 2400;
+                       break;
+               case B4800:
+                       baud = 4800;
+                       break;
+               case B9600:
+                       baud = 9600;
+                       break;
+               case B19200:
+                       baud = 19200;
+                       break;
+               case B38400:
+                       baud = 38400;
+                       break;
+               case B57600:
+                       baud = 57600;
+                       break;
+               case B115200:
+                       baud = 115200;
+                       break;
+               default:
+                       dbg ("pl2303 driver does not support the baudrate requested (fix it)");
+                       break;
+       }
+
+       if (baud) {
+               buf[0] = baud & 0xff;
+               buf[1] = (baud >> 8) & 0xff;
+               buf[2] = (baud >> 16) & 0xff;
+               buf[3] = (baud >> 24) & 0xff;
+       }
+
+
+       /* For reference buf[4]=1 is 1.5 stop bits */
+
+       if (cflag & CSTOPB) {
+               buf[4] = 2;
+       }
+
+
+       if (cflag & PARENB) {
+               /* For reference buf[5]=3 is mark parity */
+               /* For reference buf[5]=4 is space parity */
+               if (cflag & PARODD) {
+                       buf[5] = 1;
+               } else {
+                       buf[5] = 2;
+               }
+       }
+
+       i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+                            0x20, 0x21, 0, 0, buf, 7, 100);
+
+       dbg ("0x21:0x20:0:0  %d", i);
+
+       i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+                            0x22, 0x21, 1, 0, NULL, 0, 100);
+
+       dbg ("0x21:0x22:1:0  %d", i);
+
+       i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+                            0x22, 0x21, 3, 0, NULL, 0, 100);
+
+       dbg ("0x21:0x22:3:0  %d", i);
+
+       buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
+
+       i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+                            0x21, 0xa1, 0, 0, buf, 7, 100);
+
+       dbg ("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
+            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+       if (cflag & CRTSCTS) {
+
+               i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+                                    0x01, 0x40, 0x0, 0x41, NULL, 0, 100);
+
+               dbg ("0x40:0x1:0x0:0x41  %d", i);
+
+       }
+
+
+       return;
+}       
+
+
+static int
+pl2303_open (struct usb_serial_port *port, struct file *filp)
+{                              /* pl2303_open */
+       struct termios tmp_termios;
+       struct usb_serial *serial = port->serial;
+       unsigned char buf[10];
+       int i;
+
+       dbg ("pl2303_open port %d", port->number);
+
+       port->active++;
+
+#define FISH(a,b,c,d) \
+       i=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
+                   b, a,c  , d, buf, 1, 100); \
+       dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,i,buf[0]);
+
+#define SOUP(a,b,c,d) \
+       i=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
+                   b, a,c  , d, NULL, 0, 100); \
+       dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,i);
+
+
+       FISH (0xc0, 1, 0x8484, 0);
+       SOUP (0x40, 1, 0x0404, 0);
+       FISH (0xc0, 1, 0x8484, 0);
+       FISH (0xc0, 1, 0x8383, 0);
+       FISH (0xc0, 1, 0x8484, 0);
+       SOUP (0x40, 1, 0x0404, 1);
+       FISH (0xc0, 1, 0x8484, 0);
+       FISH (0xc0, 1, 0x8383, 0);
+       SOUP (0x40, 1, 0, 1);
+       SOUP (0x40, 1, 1, 0xc0);
+       SOUP (0x40, 1, 2, 4);
+
+       /* Setup termios */
+
+       if (port->active == 1) {
+               *(port->tty->termios) = tty_std_termios;
+               port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       }
+
+
+       pl2303_set_termios (port, &tmp_termios);
+
+       //FIXME: need to assert RTS and DTR if CRTSCTS off
+
+
+       if (port->active == 1) {
+               struct pl2303_private *info;
+               unsigned long flags,page;
+               int i;
+
+               info = (struct pl2303_private *)kmalloc (sizeof(struct pl2303_private), GFP_KERNEL);
+               if (info == NULL) {
+                       err(__FUNCTION__ " - out of memory");
+                       pl2303_close (port, NULL);
+                       return -ENOMEM;
+               }
+               spin_lock_init(&info->lock);
+               port->private = info;
+
+
+               page = get_free_page(GFP_KERNEL);
+               if (!page) {
+                       pl2303_close (port, NULL);
+                       return -ENOMEM;
+               }
+
+               PL2303_LOCK(port,flags);
+
+               info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+               if (tmp_buf)
+                       free_page(page);
+               else
+                       tmp_buf = (unsigned char *) page;
+
+               PL2303_UNLOCK(port,flags);
+
+               page = get_free_page(GFP_KERNEL);
+               if (!page) {
+                       pl2303_close (port, NULL);
+                       return -ENOMEM;
+               }
+
+               PL2303_LOCK(port,flags);
+
+               if (info->xmit_buf)
+                       free_page(page);
+               else
+                       info->xmit_buf=(unsigned char *) page;
+
+               PL2303_UNLOCK(port,flags);
+
+
+               if ((i = usb_submit_urb (port->read_urb))) {
+                       err ("usb_submit_urb(read bulk 1) failed");
+                       dbg ("i=%d", i);
+                       pl2303_close (port, NULL);
+                       return -EPROTO;
+
+               }
+
+               if ((i = usb_submit_urb (port->interrupt_in_urb))) {
+                       err ("usb_submit_urb(interrupt ink) failed");
+                       dbg ("i=%d", i);
+                       pl2303_close (port, NULL);
+
+                       return -EPROTO;
+               }
+       }
+
+       return(0);
+}                              /* pl2303_open */
+
+
+static void
+pl2303_close (struct usb_serial_port *port, struct file *filp)
+{                              /* pl2303_close */
+       struct pl2303_private *info;
+       unsigned int c_cflag = port->tty->termios->c_cflag;
+       unsigned long flags;
+
+       dbg ("pl2303_close port %d", port->number);
+
+       /* shutdown our bulk reads and writes */
+       if (port->active == 1) {
+
+               if (c_cflag & HUPCL) {
+                       //FIXME: Do drop DTR
+                       //FIXME: Do drop RTS
+               }
+
+               usb_unlink_urb (port->write_urb);
+               usb_unlink_urb (port->read_urb);
+               usb_unlink_urb (port->interrupt_in_urb);
+
+               info = (struct pl2303_private *)port->private;
+               if (info) {
+                       PL2303_LOCK(port,flags);
+                       if (info->xmit_buf) {
+                               unsigned char * temp;
+                               temp = info->xmit_buf;
+                               info->xmit_buf = 0;
+                               free_page((unsigned long) temp);
+                       }
+                       PL2303_UNLOCK(port,flags);
+               }
+
+               //FIXME: tmp_buf memory leak
+
+
+       }
+       port->active--;
+}                              /* pl2303_close */
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int
+pl2303_startup (struct usb_serial *serial)
+{
+       return(0);
+}
+
+
+static int
+pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+             unsigned int cmd, unsigned long arg)
+{
+// struct usb_serial *serial = port->serial;
+// __u16 urb_value=0; /* Will hold the new flags */
+// char buf[1];
+// int  ret, mask;
+
+
+       dbg ("pl2303_sio ioctl 0x%04x", cmd);
+
+       /* Based on code from acm.c and others */
+       switch (cmd) {
+               
+               case TIOCMGET:
+                       dbg ("TIOCMGET");
+
+
+                       return put_user (0, (unsigned long *) arg);
+                       break;
+               case TIOCMBIS:
+               case TIOCMBIC:
+               case TIOCMSET:
+                       return 0;
+
+               default:
+                       /* This is not an error - turns out the higher layers will do 
+                        *  some ioctls itself (see comment above)
+                        */
+                       dbg ("pl2303_sio ioctl arg not supported - it was 0x%04x", cmd);
+                       return(-ENOIOCTLCMD);
+                       break;
+       }
+       dbg ("pl2303_ioctl returning 0");
+
+       return 0;
+}                              /* pl2303_ioctl */
+
+
+static void pl2303_break_ctl(struct usb_serial_port *port,int break_state)
+{
+//FIXME
+}
+
+
+static void
+pl2303_read_int_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+       struct usb_serial *serial = get_usb_serial (port, "pl2303_read_int_callback");
+       //unsigned char *data = urb->transfer_buffer;
+       //int i;
+
+//ints auto restart...
+
+       if (!serial) {
+               return;
+       }
+
+       if (urb->status) {
+               urb->status = 0;
+               return;
+       }
+
+
+#if 0
+//FIXME need to update state of terminal lines variable
+       if (urb->actual_length) {
+               printk (KERN_DEBUG __FILE__ ": INT data read - length = %d, data = ",
+                       urb->actual_length);
+               for (i = 0; i < urb->actual_length; ++i) {
+                       printk ("%.2x ", data[i]);
+               }
+               printk ("\n");
+       }
+#endif
+
+       return;
+}
+
+static void
+pl2303_read_bulk_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+       struct usb_serial *serial = get_usb_serial (port, "pl2303_read_bulk_callback");
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+       int i;
+
+       if (!serial) {
+               return;
+       }
+
+// PL2303 mysteriously fails with -EPROTO reschedule the read
+       if (urb->status) {
+               urb->status = 0;
+               if (usb_submit_urb (urb))
+                       dbg ("failed resubmitting read bulk urb");
+               return;
+       }
+
+       if (debug) {
+               if (urb->actual_length) {
+                       printk (KERN_DEBUG __FILE__ ": BULK data read - length = %d, data = ",
+                               urb->actual_length);
+                       for (i = 0; i < urb->actual_length; ++i) {
+                               printk ("%.2x ", data[i]);
+                       }
+                       printk ("\n");
+               }
+       }
+
+       tty = port->tty;
+       if (urb->actual_length) {
+               for (i = 0; i < urb->actual_length; ++i) {
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               dbg ("ARGH ------------ Flip buffer overrun...");
+
+                               break;
+                       }
+                       tty_insert_flip_char (tty, data[i], 0);
+               }
+               tty_flip_buffer_push (tty);
+       }
+
+
+       /* Schedule the next read*/
+       if (usb_submit_urb (urb))
+               dbg ("failed submitting read bulk urb");
+
+       return;
+}
+
+
+
+static void
+pl2303_write_bulk_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+       struct usb_serial *serial;
+       struct tty_struct *tty = port->tty;
+
+       dbg ("pl2303_write_bulk_callback");
+
+
+       if (port_paranoia_check (port, "pl2303_write_bulk_callback")) {
+               return;
+       }
+
+       serial = port->serial;
+       if (serial_paranoia_check (serial, "pl2303_write_bulk_callback")) {
+               return;
+       }
+
+
+       if (urb->status) {
+               dbg ("Overflow in write");
+               dbg ("nonzero write bulk status received: %d", urb->status);
+               //need to resubmit frame;
+
+               port->write_urb->transfer_buffer_length = 1;
+
+               //Resubmit ourselves
+
+               if (usb_submit_urb (port->write_urb))
+                       err ("usb_submit_urb(write bulk) failed");
+
+               return;
+       }
+
+       wake_up_interruptible (&port->write_wait);
+
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+               (tty->ldisc.write_wakeup) (tty);
+
+       wake_up_interruptible (&tty->write_wait);
+
+       start_xmit(port);
+
+       return;
+}
+
+
+
+static void
+start_xmit (struct usb_serial_port *port)
+{
+       struct usb_serial *serial;
+       struct pl2303_private *info;
+       unsigned long flags;
+
+       serial = port->serial;
+       info = (struct pl2303_private *)port->private;
+
+       if (info) {
+               PL2303_LOCK(port,flags);
+
+               if (port->write_urb->status != -EINPROGRESS) {
+                       if (info->xmit_tail != info->xmit_head) {
+
+                               memcpy (port->write_urb->transfer_buffer, &info->xmit_buf[info->xmit_tail],1);
+                               info->xmit_cnt--;
+                               info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+
+
+                               port->write_urb->transfer_buffer_length = 1;
+
+
+                               if (usb_submit_urb (port->write_urb))
+                                       err ("usb_submit_urb(write bulk) failed");
+
+
+                       }
+               }
+
+               PL2303_UNLOCK(port,flags);
+       }
+}
+
+
+static int __init pl2303_init (void)
+{
+       usb_serial_register (&pl2303_device);
+       info(DRIVER_VERSION " : " DRIVER_DESC);
+       return 0;
+}
+
+
+static void __exit pl2303_exit (void)
+{
+       usb_serial_deregister (&pl2303_device);
+}
+
+
+module_init(pl2303_init);
+module_exit(pl2303_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
index 65ae21175d0a6afa336f737cf4f18beb30339e80..7d1cd90f2d405598e732f0c2e0b31f9ac335e25e 100644 (file)
@@ -2585,15 +2585,15 @@ ohci_pci_remove (struct pci_dev *dev)
 
 /*-------------------------------------------------------------------------*/
 
-static void
-ohci_pci_suspend (struct pci_dev *dev)
+static int
+ohci_pci_suspend (struct pci_dev *dev, u32 state)
 {
        ohci_t          *ohci = (ohci_t *) dev->driver_data;
 
        if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
                dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
                        hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
-               return;
+               return -EIO;
        }
 
        /* act as if usb suspend can always be used */
@@ -2605,11 +2605,13 @@ ohci_pci_suspend (struct pci_dev *dev)
        ohci->hc_control = OHCI_USB_SUSPEND;
        writel (ohci->hc_control, &ohci->regs->control);
        wait_ms (10);
+
+       return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void
+static int
 ohci_pci_resume (struct pci_dev *dev)
 {
        ohci_t          *ohci = (ohci_t *) dev->driver_data;
@@ -2620,7 +2622,7 @@ ohci_pci_resume (struct pci_dev *dev)
        if (atomic_read (&ohci->resume_count) != 1) {
                err ("concurrent PCI resumes for usb-%s", dev->slot_name);
                atomic_dec (&ohci->resume_count);
-               return;
+               return -EBUSY;
        }
 
        /* did we suspend, or were we powered off? */
@@ -2653,7 +2655,7 @@ ohci_pci_resume (struct pci_dev *dev)
                if (temp != OHCI_USB_RESUME) {
                        err ("controller usb-%s won't resume", dev->slot_name);
                        ohci->disabled = 1;
-                       return;
+                       return -EIO;
                }
 
                ohci->disabled = 0;
@@ -2676,6 +2678,8 @@ ohci_pci_resume (struct pci_dev *dev)
 
        /* controller is operational, extra resumes are harmless */
        atomic_dec (&ohci->resume_count);
+
+       return 0;
 }
 
 #endif /* CONFIG_PM */
index caa44f141df32c81b9525b02c873d67b36b09aae..4aa3080d39c263c73bb9a25267c8f9a17b2a900a 100644 (file)
@@ -2897,16 +2897,18 @@ _static int __init uhci_start_usb (uhci_t *s)
 }
 
 #ifdef CONFIG_PM
-_static void
-uhci_pci_suspend (struct pci_dev *dev)
+_static int
+uhci_pci_suspend (struct pci_dev *dev, u32 state)
 {
        reset_hc((uhci_t *) dev->driver_data);
+       return 0;
 }
 
-_static void
+_static int
 uhci_pci_resume (struct pci_dev *dev)
 {
        start_hc((uhci_t *) dev->driver_data);
+       return 0;
 }
 #endif
 
index d8c524e760d1a48e2ea6a7f3e269052f6970b4c2..97d0ed375dc10a36c8074771b272ebeed63f76be 100644 (file)
@@ -1612,14 +1612,15 @@ static void __devexit cyberpro_remove(struct pci_dev *dev)
        }
 }
 
-static void cyberpro_suspend(struct pci_dev *dev)
+static int cyberpro_suspend(struct pci_dev *dev, u32 state)
 {
+       return 0;
 }
 
 /*
  * Re-initialise the CyberPro hardware
  */
-static void cyberpro_resume(struct pci_dev *dev)
+static int cyberpro_resume(struct pci_dev *dev)
 {
        struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
 
@@ -1633,6 +1634,8 @@ static void cyberpro_resume(struct pci_dev *dev)
                cfb->fb.var.activate = FB_ACTIVATE_NOW;
                cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
        }
+
+       return 0;
 }
 
 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
index a68f1cb03359d1f9b37a2b563938d63c2a2187dc..2b1c2cbd908252431a0d8417c83a13b35da70d8b 100644 (file)
@@ -6,6 +6,7 @@
  *  With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu)
  *  Modified by Danilo Beuche 1998
  *  Some register values added by Damien Doligez, INRIA Rocquencourt
+ *  Various cleanups by Paul Mundt (lethal@chaoticdreams.org)
  *
  *  This file was written by Ryan Nielsen (ran@krazynet.com)
  *  Most of the frame buffer device stuff was copied from atyfb.c
@@ -378,6 +379,7 @@ enum {
 #define CURSOR_DRAW_DELAY      2
 
 static int currcon = 0;
+static int inverse = 0;
 static char fontname[40] __initdata = { 0 };
 static char curblink __initdata = 1;
 static char noaccel __initdata = 0;
@@ -1235,7 +1237,6 @@ imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue,
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
        u_int bpp = fb_display[currcon].var.bits_per_pixel;
-       u_int i;
 
        if (regno > 255)
                return 1;
@@ -1413,7 +1414,7 @@ set_disp (struct display *disp, struct fb_info_imstt *p)
        disp->type_aux = p->fix.type_aux;
        disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
        disp->can_soft_blank = 1;
-       disp->inverse = 0;
+       disp->inverse = inverse;
        disp->ypanstep = 1;
        disp->ywrapstep = 0;
        if (accel) {
@@ -1887,7 +1888,6 @@ imsttfb_init(void)
        struct pci_dev *pdev = NULL;
        struct fb_info_imstt *p;
        unsigned long addr, size;
-       __u16 cmd;
 
        while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
                if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
@@ -1963,6 +1963,9 @@ imsttfb_setup(char *options)
                        curblink = 0;
                } else if (!strncmp(this_opt, "noaccel", 7)) {
                        noaccel = 1;
+               } else if (!strncmp(this_opt, "inverse", 7)) {
+                       inverse = 1;
+                       fb_invert_cmaps();
                }
 #if defined(CONFIG_PPC)
                else if (!strncmp(this_opt, "vmode:", 6)) {
@@ -1994,16 +1997,8 @@ imsttfb_setup(char *options)
 }
 
 #else /* MODULE */
-
-int __init
-init_module (void)
-{
-
-       return imsttfb_init();
-}
-
-void
-cleanup_module (void)
+static void __exit
+imsttfb_exit(void)
 {
        struct fb_info_imstt *p;
        __u32 i;
@@ -2012,13 +2007,18 @@ cleanup_module (void)
                p = fb_info_imstt_p[i];
                if (!p)
                        continue;
+               unregister_framebuffer(&p->info);
                iounmap(p->cmap_regs);
                iounmap(p->dc_regs);
                iounmap(p->frame_buffer);
-               kfree(p);
                release_mem_region(p->frame_buffer_phys, p->board_size);
+               kfree(p);
        }
 }
 
 #include "macmodes.c"
+
+module_init(imsttfb_init);
+module_exit(imsttfb_exit);
 #endif /* MODULE */
+
index af2d13b2049582d4c12769b93c8e684f4e28f124..159d5a7a61c5cc8221251ef311a834109d5506c3 100644 (file)
@@ -94,7 +94,15 @@ static const struct fb_videomode mac_modedb[] = {
        /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
        "mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3,
        FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-    },
+    }, {
+       /* 1152x768, 60 Hz, Titanium PowerBook */
+       "mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+       /* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */
+       "mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }
 
 #if 0
     /* Anyone who has timings for these? */
@@ -154,12 +162,16 @@ static const struct mode_map {
     { VMODE_1024_768_75V, &mac_modedb[9] },
     { VMODE_1024_768_70, &mac_modedb[8] },
     { VMODE_1024_768_60, &mac_modedb[7] },
+    /* 1152x768 */
+    { VMODE_1152_768_60, &mac_modedb[14] },
     /* 1152x870 */
     { VMODE_1152_870_75, &mac_modedb[11] },
     /* 1280x960 */
     { VMODE_1280_960_75, &mac_modedb[12] },
     /* 1280x1024 */
     { VMODE_1280_1024_75, &mac_modedb[13] },
+    /* 1600x1024 */
+    { VMODE_1600_1024_60, &mac_modedb[15] },
     { -1, NULL }
 };
 
@@ -191,6 +203,7 @@ static const struct monitor_map {
     { 0x730, VMODE_768_576_50I },      /* PAL (Alternate) */
     { 0x73a, VMODE_1152_870_75 },      /* 3rd party 19" */
     { 0x73f, VMODE_640_480_67 },       /* no sense lines connected at all */
+    { 0xBEEF, VMODE_1600_1024_60 },    /* 22" Apple Cinema Display */
     { -1,    VMODE_640_480_60 },       /* catch-all, must be last */
 };
 
index 24d5a7db804efa7846a358c9af0454687524d4c4..a724411ec009a44520a11ea8daff411778178925 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.52 2001/02/02
+ * Version: 1.53 2001/06/18
  *
  * See matroxfb_base.c for contributors.
  *
 #define DAC1064_OPT_RESERVED   0x10
 
 static void matroxfb_DAC1064_flashcursor(unsigned long ptr) {
+       unsigned long flags;
+
 #define minfo ((struct matrox_fb_info*)ptr)
-       matroxfb_DAC_lock();
+       matroxfb_DAC_lock_irqsave(flags);
        outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA);
        ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
        add_timer(&ACCESS_FBINFO(cursor.timer));
-       matroxfb_DAC_unlock();
+       matroxfb_DAC_unlock_irqrestore(flags);
 #undef minfo
 }
 
@@ -719,7 +721,8 @@ static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
        ACCESS_FBINFO(capable.vxres) = vxres_g100;
        ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
        ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
-       ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100;
+       ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
+                       ? ACCESS_FBINFO(devflags.sgram) : 1;
 
        ACCESS_FBINFO(primout) = &m1064;
 
index 7c65eaa0f982da4d7729c55fd8c216bfa9cfce6e..b5172699ddf55c92b6ac97c960846ad7a5fbf3e5 100644 (file)
@@ -279,12 +279,14 @@ static const unsigned char MGADACbpp32[] =
   0x00, 0x00, TVP3026_XCURCTRL_DIS };
 
 static void matroxfb_ti3026_flashcursor(unsigned long ptr) {
+       unsigned long flags;
+
 #define minfo ((struct matrox_fb_info*)ptr)
-       matroxfb_DAC_lock();
+       matroxfb_DAC_lock_irqsave(flags);
        outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA);
        ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
        add_timer(&ACCESS_FBINFO(cursor.timer));
-       matroxfb_DAC_unlock();
+       matroxfb_DAC_unlock_irqrestore(flags);
 #undef minfo
 }
 
index d79e5e3e48b875812e7590529a8136f52dcf0867..8af7d5c338862e1f931fdb33e1b905028c125c5a 100644 (file)
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.50 2000/08/10
+ * Version: 1.51 2001/06/18
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -129,6 +129,10 @@ void matrox_cfbX_init(WPMINFO struct display* p) {
        mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
        if (ACCESS_FBINFO(capable.plnwt))
                mga_outl(M_PLNWT, -1);
+       if (ACCESS_FBINFO(capable.srcorg)) {
+               mga_outl(M_SRCORG, 0);
+               mga_outl(M_DSTORG, 0);
+       }
        mga_outl(M_OPMODE, mopmode);
        mga_outl(M_CXBNDRY, 0xFFFF0000);
        mga_outl(M_YTOP, 0);
index 532a644efcfb3987bd24ed266cae5c297278b254..b2823794b38a9d471a1ff3ec575bc2be78915a47 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.52 2001/02/02
+ * Version: 1.53 2001/06/18
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -72,6 +72,9 @@
  *               "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
  *                     memtype extension (needed for GXT130P RS/6000 adapter)
  *
+ *               "Uns Lider" <unslider@miranda.org>
+ *                     G100 PLNWT fixes
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -1409,7 +1412,7 @@ static struct video_board vbG400          = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
 
 #define DEVF_VIDEO64BIT                0x0001
 #define        DEVF_SWAPS              0x0002
-/* #define DEVF_recycled       0x0004 */
+#define DEVF_SRCORG            0x0004
 /* #define DEVF_recycled       0x0008 */
 #define DEVF_CROSS4MB          0x0010
 #define DEVF_TEXT4B            0x0020
@@ -1424,12 +1427,12 @@ static struct video_board vbG400                = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
 #define DEVF_G450DAC           0x4000
 
 #define DEVF_GCORE     (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
-#define DEVF_G2CORE    (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE)
+#define DEVF_G2CORE    (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
 #define DEVF_G100      (DEVF_GCORE) /* no doc, no vxres... */
 #define DEVF_G200      (DEVF_G2CORE)
 #define DEVF_G400      (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
 /* if you'll find how to drive DFP... */
-#define DEVF_G450      (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC)
+#define DEVF_G450      (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG)
 
 static struct board {
        unsigned short vendor, device, rev, svid, sid;
@@ -1556,7 +1559,7 @@ static struct board {
                DEVF_G200,
                230000,
                &vbG200,
-               "unknown G200 (AGP)"},
+               "G200 (AGP)"},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G400_AGP,  0x80,
                PCI_SS_VENDOR_ID_MATROX,        PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
                DEVF_G400,
@@ -1568,13 +1571,13 @@ static struct board {
                DEVF_G400,
                300000,
                &vbG400,
-               "unknown G400 (AGP)"},
+               "G400 (AGP)"},
        {PCI_VENDOR_ID_MATROX,  PCI_DEVICE_ID_MATROX_G400_AGP,  0xFF,
                0,                      0,
                DEVF_G450,
                500000,         /* ??? vco goes up to 900MHz... */
                &vbG400,
-               "unknown G450 (AGP)"},
+               "G450 (AGP)"},
 #endif
        {0,                     0,                              0xFF,
                0,                      0,
@@ -1611,6 +1614,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
 
        printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
        ACCESS_FBINFO(capable.plnwt) = 1;
+       ACCESS_FBINFO(capable.srcorg) = b->flags & DEVF_SRCORG;
        ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
        if (b->flags & DEVF_TEXT4B) {
                ACCESS_FBINFO(devflags.vgastep) = 4;
@@ -2483,7 +2487,7 @@ int __init matroxfb_setup(char *options) {
        return 0;
 }
 
-static int initialized __initdata = 0;
+static int __initdata initialized = 0;
 
 int __init matroxfb_init(void)
 {
@@ -2495,6 +2499,7 @@ int __init matroxfb_init(void)
                initialized = 1;
                matrox_init();
        }
+       hotplug = 1;
        /* never return failure, user can hotplug matrox later... */
        return 0;
 }
@@ -2526,7 +2531,7 @@ MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matro
 MODULE_PARM(mtrr, "i");
 MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
 MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
 MODULE_PARM(inv24, "i");
 MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
 MODULE_PARM(inverse, "i");
index 20c627905c31e0427b4d38e5468ae0c789c0baef..a6048a7931acd16380f439cbc339d8be8341c492 100644 (file)
@@ -492,6 +492,7 @@ struct matrox_fb_info {
                int             cross4MB;
                int             text;
                int             plnwt;
+               int             srcorg;
                              } capable;
        struct {
                unsigned int    size;
@@ -738,6 +739,7 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv);
 
 /* G200 only */
 #define M_SRCORG       0x2CB4
+#define M_DSTORG       0x2CB8
 
 #define M_RAMDAC_BASE  0x3C00
 
index 8640289b1276825d4adddf84665a830c54216a29..c05be34212a4b57e70a7821d3c5a8ad36854f65c 100644 (file)
@@ -6,17 +6,20 @@
 
 static int matroxfb_g450_get_reg(WPMINFO int reg) {
        int val;
+       unsigned long flags;
 
-       matroxfb_DAC_lock();
+       matroxfb_DAC_lock_irqsave(flags);
        val = matroxfb_DAC_in(PMINFO reg);
-       matroxfb_DAC_unlock();
+       matroxfb_DAC_unlock_irqrestore(flags);
        return val;
 }
 
 static int matroxfb_g450_set_reg(WPMINFO int reg, int val) {
-       matroxfb_DAC_lock();
+       unsigned long flags;
+
+       matroxfb_DAC_lock_irqsave(flags);
        matroxfb_DAC_out(PMINFO reg, val);
-       matroxfb_DAC_unlock();
+       matroxfb_DAC_unlock_irqrestore(flags);
        return 0;
 }
 
index bbb046178c1cacbdadeb503cafd18de77b473541..f869850407369b090a265b19298230af82d0d288 100644 (file)
@@ -21,6 +21,9 @@
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive for
  *  more details.
+ *
+ *  Changelog:
+ *  Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
  */
 
 #include <linux/types.h>
@@ -129,6 +132,7 @@ static void write_mda_w(unsigned int val, unsigned char reg)
        spin_unlock_irqrestore(&mda_lock, flags);
 }
 
+#ifdef TEST_MDA_B
 static int test_mda_b(unsigned char val, unsigned char reg)
 {
        unsigned long flags;
@@ -143,6 +147,7 @@ static int test_mda_b(unsigned char val, unsigned char reg)
        spin_unlock_irqrestore(&mda_lock, flags);
        return val;
 }
+#endif
 
 static inline void mda_set_origin(unsigned int location)
 {
@@ -182,20 +187,27 @@ static inline void mda_set_cursor_size(int from, int to)
 
 
 #ifndef MODULE
-void __init mdacon_setup(char *str, int *ints)
+static int __init mdacon_setup(char *str)
 {
        /* command line format: mdacon=<first>,<last> */
 
+       int ints[3];
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
        if (ints[0] < 2)
-               return;
+               return 0;
 
        if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || 
            ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
-               return;
+               return 0;
 
-       mda_first_vc = ints[1]-1;
-       mda_last_vc  = ints[2]-1;
+       mda_first_vc = ints[1];
+       mda_last_vc  = ints[2];
+       return 1;
 }
+
+__setup("mdacon=", mdacon_setup);
 #endif
 
 static int __init mda_detect(void)
@@ -237,17 +249,19 @@ static int __init mda_detect(void)
         * memory location, so now we do an I/O port test.
         */
 
+#ifdef TEST_MDA_B
        /* Edward: These two mess `tests' mess up my cursor on bootup */
 
        /* cursor low register */
-       /* if (! test_mda_b(0x66, 0x0f)) {
+       if (! test_mda_b(0x66, 0x0f)) {
                return 0;
-       } */
+       }
 
        /* cursor low register */
-       /* if (! test_mda_b(0x99, 0x0f)) {
+       if (! test_mda_b(0x99, 0x0f)) {
                return 0;
-       } */
+       }
+#endif
 
        /* See if the card is a Hercules, by checking whether the vsync
         * bit of the status register is changing.  This test lasts for
index e23ddbca3a827a93b83ea02cb25c8beb2501f09f..5eebc138254102ba7931ded724a1acf65c3d0f8e 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_bmap.c,v 1.20 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_bmap.c,v 1.22 2001/05/26 22:41:23 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - filesystem to disk block mapping.
@@ -70,7 +70,7 @@ vxfs_bmap_ext4(struct inode *ip, long iblock)
        struct super_block              *sbp = ip->i_sb;
        kdev_t                          dev = ip->i_dev;
        u_long                          bsize = sbp->s_blocksize;
-       u_long                          size = 0;
+       long                            size = 0;
        int                             i;
 
        for (i = 0; i < VXFS_NDADDR; i++) {
@@ -135,7 +135,7 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
 
        for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
                struct vxfs_typed       *typ;
-               u_int64_t               off;
+               int64_t                 off;
 
                bp = bread(ip->i_dev,
                                indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)),
@@ -166,10 +166,12 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
                        goto out;
                case VXFS_TYPED_INDIRECT_DEV4:
                case VXFS_TYPED_DATA_DEV4: {
-                       struct vxfs_typed_dev4  *typ4 = (struct vxfs_typed_dev4 *)typ;
+                       struct vxfs_typed_dev4  *typ4 =
+                               (struct vxfs_typed_dev4 *)typ;
+
                        printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-                       printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
-                              (long long)typ4->vd4_block, (long long)typ4->vd4_size, typ4->vd4_dev);
+                       printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+                               typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
                        goto fail;
                }
                default:
@@ -205,7 +207,7 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
 
        for (i = 0; i < VXFS_NTYPED; i++) {
                struct vxfs_typed       *typ = vip->vii_org.typed + i;
-               u_int64_t               off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+               int64_t                 off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
 
 #ifdef DIAGNOSTIC
                vxfs_typdump(typ);
@@ -225,10 +227,12 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
                        break;
                case VXFS_TYPED_INDIRECT_DEV4:
                case VXFS_TYPED_DATA_DEV4: {
-                       struct vxfs_typed_dev4  *typ4 = (struct vxfs_typed_dev4 *)typ;
+                       struct vxfs_typed_dev4  *typ4 =
+                               (struct vxfs_typed_dev4 *)typ;
+
                        printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-                       printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
-                              (long long)typ4->vd4_block, (long long)typ4->vd4_size, typ4->vd4_dev);
+                       printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+                               typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
                        return 0;
                }
                default:
index 23edf443cc4f510bb558d752a9350d15f01018d2..28fc5c6a586c745fd23ba2f0fb5f7e776f356f27 100644 (file)
@@ -30,7 +30,7 @@
 #ifndef _VXFS_FSHEAD_H_
 #define _VXFS_FSHEAD_H_
 
-#ident "$Id: vxfs_fshead.h,v 1.6 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_fshead.h,v 1.7 2001/05/23 17:27:39 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - fileset header structures.
@@ -61,8 +61,8 @@ struct vxfs_fsh {
 
        /*
         * Slightly more fields follow, but they
-        *  a) are not of any interested for us, and
-        *  b) differ much in different vxfs versions/ports
+        *  a) are not of any interest for us, and
+        *  b) differ a lot in different vxfs versions/ports
         */
 };
 
index 4790a631d94860a396d37000eb17e3986678475e..c4103da5ded5606fb8d8e68e828217dfb42cedd2 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_inode.c,v 1.34 2001/05/21 15:33:08 hch Exp hch $"
+#ident "$Id: vxfs_inode.c,v 1.36 2001/05/26 22:28:02 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - inode routines.
@@ -47,6 +47,7 @@ extern struct address_space_operations vxfs_immed_aops;
 extern struct inode_operations vxfs_immed_symlink_iops;
 
 static struct file_operations vxfs_file_operations = {
+       .llseek =               generic_file_llseek,
        .read =                 generic_file_read,
        .mmap =                 generic_file_mmap,
 };
@@ -91,7 +92,7 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
  *  Returns the matching VxFS inode on success, else a NULL pointer.
  *
  * NOTE:
- *  While __vxfs_iget uses that pagecache this function uses the
+ *  While __vxfs_iget uses the pagecache vxfs_blkiget uses the
  *  buffercache.  This function should not be used outside the
  *  read_super() method, othwerwise the data may be incoherent.
  */
@@ -138,7 +139,7 @@ fail:
  *  Returns the matching VxFS inode on success, else a NULL pointer.
  */
 static struct vxfs_inode_info *
-__vxfs_iget(struct super_block *sbp, ino_t ino, struct inode *ilistp)
+__vxfs_iget(ino_t ino, struct inode *ilistp)
 {
        struct page                     *pp;
        u_long                          offset;
@@ -184,7 +185,7 @@ fail:
 struct vxfs_inode_info *
 vxfs_stiget(struct super_block *sbp, ino_t ino)
 {
-        return __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_stilist);
+        return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
 }
 
 /**
@@ -288,7 +289,7 @@ vxfs_read_inode(struct inode *ip)
        struct address_space_operations *aops;
        ino_t                           ino = ip->i_ino;
 
-       if (!(vip = __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_ilist)))
+       if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
                return;
 
        vxfs_iinit(ip, vip);
index 9210dc95af57448a1674a191b60b18a8917d123c..e7d2fc114c2c4f522b647add670136711d3cb777 100644 (file)
@@ -30,7 +30,7 @@
 #ifndef _VXFS_INODE_H_
 #define _VXFS_INODE_H_
 
-#ident "$Id: vxfs_inode.h,v 1.14 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_inode.h,v 1.15 2001/05/26 22:41:23 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - inode structure.
@@ -77,7 +77,7 @@ struct vxfs_ext4 {
        vx_daddr_t              ve4_indir[VXFS_NIADDR]; /* Indirect extents */
        struct direct {                                 /* Direct extents */
                vx_daddr_t      extent;                 /* Extent number */
-               u_int32_t       size;                   /* Size of extent */
+               int32_t         size;                   /* Size of extent */
        } ve4_direct[VXFS_NDADDR];
 };
 
index 6a17d5b8c08814fde9f7421b8d73e9e8a7f120d8..bc64fd8b527d7a9dd8dcd5fd09577fb29f700ff0 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_lookup.c,v 1.17 2001/05/21 15:23:53 hch Exp hch $"
+#ident "$Id: vxfs_lookup.c,v 1.19 2001/05/30 19:50:20 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - lookup and other directory related code.
@@ -240,9 +240,8 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
        struct inode            *ip = fp->f_dentry->d_inode;
        struct super_block      *sbp = ip->i_sb;
        u_long                  bsize = sbp->s_blocksize;
-       u_long                  page, npages, block, nblocks, offset;
+       u_long                  page, npages, block, pblocks, nblocks, offset;
        loff_t                  pos;
-       int                     pblocks;
 
        switch ((long)fp->f_pos) {
        case 0:
@@ -262,14 +261,14 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
        if (pos > VXFS_DIRROUND(ip->i_size))
                return 0;
 
-       page = pos >> PAGE_CACHE_SHIFT;
-       offset = pos & ~PAGE_CACHE_MASK;
-       block = pos >> sbp->s_blocksize_bits;
-
        npages = dir_pages(ip);
        nblocks = dir_blocks(ip);
        pblocks = VXFS_BLOCK_PER_PAGE(sbp);
 
+       page = pos >> PAGE_CACHE_SHIFT;
+       offset = pos & ~PAGE_CACHE_MASK;
+       block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
+
        for (; page < npages; page++, block = 0) {
                caddr_t                 kaddr;
                struct page             *pp;
@@ -310,6 +309,7 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
                                        goto done;
                                }
                        }
+                       offset = 0;
                }
                vxfs_put_page(pp);
                offset = 0;
index d69f9ff08adc3f5b65d85eb65e0bdbaa088bd916..f76c472fb71a298708e96e82b401907be3d2fe74 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_super.c,v 1.24 2001/05/20 15:21:14 hch Exp hch $"
+#ident "$Id: vxfs_super.c,v 1.25 2001/05/25 18:25:55 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - superblock related routines.
@@ -168,18 +168,18 @@ vxfs_read_super(struct super_block *sbp, void *dp, int silent)
        bp = bread(dev, 1, bsize);
        if (!bp) {
                printk(KERN_WARNING "vxfs: unable to read disk superblock\n");
-               return NULL;
+               goto out;
        }
 
        rsbp = (struct vxfs_sb *)bp->b_data;
        if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
                printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
-               return NULL;
+               goto out;
        }
 
        if (rsbp->vs_version < 2 || rsbp->vs_version > 4) {
                printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", rsbp->vs_version);
-               return NULL;
+               goto out;
        }
 
 #ifdef DIAGNOSTIC
@@ -210,12 +210,12 @@ vxfs_read_super(struct super_block *sbp, void *dp, int silent)
        default:
                printk(KERN_WARNING "vxfs: unsupported blocksise: %d\n",
                                rsbp->vs_bsize);
-               return NULL;
+               goto out;
        }
 
        if (vxfs_read_olt(sbp, bsize)) {
                printk(KERN_WARNING "vxfs: unable to read olt\n");
-               return NULL;
+               goto out;
        }
 
        if (vxfs_read_fshead(sbp)) {
@@ -228,6 +228,8 @@ vxfs_read_super(struct super_block *sbp, void *dp, int silent)
                return (sbp);
        
        printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
+out:
+       kfree(infp);
        return NULL;
 }
 
index fc5f7d5fb4eef98d44ababb7dc7f9c9489b43274..a3a66de49088d91dde436deb94202c8241a116dc 100644 (file)
@@ -16,6 +16,7 @@
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
  *
+ * Copyright 2000, 2001  Red Hat, Inc.
  */
 
 /* inode.c -- Contains the code that is called from the VFS.  */
@@ -1719,9 +1720,6 @@ static DECLARE_FSTYPE_DEV(jffs_fs_type, "jffs", jffs_read_super);
 static int __init
 init_jffs_fs(void)
 {
-       printk("JFFS version "
-              JFFS_VERSION_STRING
-              ", (C) 1999, 2000  Axis Communications AB\n");
        return register_filesystem(&jffs_fs_type);
 }
 
index cf9e41cc42c2c462a7cad63780afd62f41e808b0..9d16d856fb8a875567e0bbf754c58e7f846e4ec0 100644 (file)
@@ -29,7 +29,7 @@ if [ "$CONFIG_NLS" = "y" ]; then
   tristate 'Codepage 852 (Central/Eastern Europe)' CONFIG_NLS_CODEPAGE_852
   tristate 'Codepage 855 (Cyrillic)'               CONFIG_NLS_CODEPAGE_855
   tristate 'Codepage 857 (Turkish)'                CONFIG_NLS_CODEPAGE_857
-  tristate 'Codepage 860 (Portugese)'              CONFIG_NLS_CODEPAGE_860
+  tristate 'Codepage 860 (Portuguese)'             CONFIG_NLS_CODEPAGE_860
   tristate 'Codepage 861 (Icelandic)'              CONFIG_NLS_CODEPAGE_861
   tristate 'Codepage 862 (Hebrew)'                 CONFIG_NLS_CODEPAGE_862
   tristate 'Codepage 863 (Canadian French)'        CONFIG_NLS_CODEPAGE_863
@@ -43,7 +43,7 @@ if [ "$CONFIG_NLS" = "y" ]; then
   tristate 'Korean charset (CP949, EUC-KR)'        CONFIG_NLS_CODEPAGE_949
   tristate 'Thai charset (CP874, TIS-620)'         CONFIG_NLS_CODEPAGE_874
   tristate 'Hebrew charsets (ISO-8859-8, CP1255)'  CONFIG_NLS_ISO8859_8
-  tristate 'Windows CP1251 (Bulgarian, Belarussian)' CONFIG_NLS_CODEPAGE_1251
+  tristate 'Windows CP1251 (Bulgarian, Belarusian)' CONFIG_NLS_CODEPAGE_1251
   tristate 'NLS ISO 8859-1  (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
   tristate 'NLS ISO 8859-2  (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2
   tristate 'NLS ISO 8859-3  (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3
@@ -56,7 +56,7 @@ if [ "$CONFIG_NLS" = "y" ]; then
   tristate 'NLS ISO 8859-14 (Latin 8; Celtic)'      CONFIG_NLS_ISO8859_14
   tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
   tristate 'NLS KOI8-R (Russian)'                   CONFIG_NLS_KOI8_R
-  tristate 'NLS KOI8-U/RU (Ukrainian, Belarussian)' CONFIG_NLS_KOI8_U
+  tristate 'NLS KOI8-U/RU (Ukrainian, Belarusian)' CONFIG_NLS_KOI8_U
   tristate 'NLS UTF8'                               CONFIG_NLS_UTF8
   endmenu
 fi
index 90b78687d227da3114d7ba6d04e40a906767b2b5..94bdc4f54fcdb80b35a04966888012ba7a6ab90b 100644 (file)
@@ -312,6 +312,13 @@ static struct file_operations proc_info_file_operations = {
 #define MAY_PTRACE(p) \
 (p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
 
+
+static int mem_open(struct inode* inode, struct file* file)
+{
+       file->private_data = (void*)(current->self_exec_id);
+       return 0;
+}
+
 static ssize_t mem_read(struct file * file, char * buf,
                        size_t count, loff_t *ppos)
 {
@@ -319,6 +326,8 @@ static ssize_t mem_read(struct file * file, char * buf,
        char *page;
        unsigned long src = *ppos;
        int copied = 0;
+       struct mm_struct *mm;
+
 
        if (!MAY_PTRACE(task))
                return -ESRCH;
@@ -327,6 +336,18 @@ static ssize_t mem_read(struct file * file, char * buf,
        if (!page)
                return -ENOMEM;
 
+       task_lock(task);
+       mm = task->mm;
+       if (mm)
+               atomic_inc(&mm->mm_users);
+       task_unlock(task);
+
+       if (file->private_data != (void*)(current->self_exec_id) ) {
+               mmput(mm);
+               return -EIO;
+       }
+               
+
        while (count > 0) {
                int this_len, retval;
 
@@ -347,6 +368,7 @@ static ssize_t mem_read(struct file * file, char * buf,
                count -= retval;
        }
        *ppos = src;
+       mmput(mm);
        free_page((unsigned long) page);
        return copied;
 }
@@ -398,6 +420,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
 static struct file_operations proc_mem_operations = {
        read:           mem_read,
        write:          mem_write,
+       open:           mem_open,
 };
 
 static struct inode_operations proc_mem_inode_operations = {
index ff6918ce1786b5ed2ae5c26c456656fcef603f8e..8fe752c075e7fa430a48ec69715bc135b1989bda 100644 (file)
@@ -192,13 +192,22 @@ static int xlate_proc_name(const char *name,
 
 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8];
 
+spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED;
+
 static int make_inode_number(void)
 {
-       int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
-       if (i<0 || i>=PROC_NDYNAMIC) 
-               return -1;
+       int i;
+       spin_lock(&proc_alloc_map_lock);
+       i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
+       if (i<0 || i>=PROC_NDYNAMIC) {
+               i = -1;
+               goto out;
+       }
        set_bit(i, (void *) proc_alloc_map);
-       return PROC_DYNAMIC_FIRST + i;
+       i += PROC_DYNAMIC_FIRST;
+out:
+       spin_unlock(&proc_alloc_map_lock);
+       return i;
 }
 
 static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
index b42450eb0a3365b3d2ce36aba64af8e124cd6d11..99b1828b6589c2495f93ea36c8130b054835daca 100644 (file)
@@ -260,7 +260,7 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
        fd_set_bits fds;
        char *bits;
        long timeout;
-       int ret, size;
+       int ret, size, max_fdset;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
@@ -285,8 +285,10 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
        if (n < 0)
                goto out_nofds;
 
-       if (n > current->files->max_fdset)
-               n = current->files->max_fdset;
+       /* max_fdset can increase, so grab it once to avoid race */
+       max_fdset = current->files->max_fdset;
+       if (n > max_fdset)
+               n = max_fdset;
 
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
index 9bfe93269b4b78afa8f7a415198009c89bae91b2..2ad747a6a0ed61a03a3a6fcba65c0383d21e41b5 100644 (file)
  * Function prototypes to keep gcc -Wall happy.
  */
 extern void set_bit(int nr, volatile void * addr);
+
+static inline void __set_bit(int nr, volatile void *addr)
+{
+       ((unsigned char *) addr)[nr >> 3] |= (1U << (nr & 7));
+}
+
 extern void clear_bit(int nr, volatile void * addr);
+
+static inline void __clear_bit(int nr, volatile void *addr)
+{
+       ((unsigned char *) addr)[nr >> 3] &= ~(1U << (nr & 7));
+}
+
 extern void change_bit(int nr, volatile void * addr);
 
+static inline void __change_bit(int nr, volatile void *addr)
+{
+       ((unsigned char *) addr)[nr >> 3] ^= (1U << (nr & 7));
+}
+
 extern int test_and_set_bit(int nr, volatile void * addr);
+
+static inline int __test_and_set_bit(int nr, volatile void *addr)
+{
+       unsigned int mask = 1 << (nr & 7);
+       unsigned int oldval;
+
+       oldval = ((unsigned char *) addr)[nr >> 3];
+       ((unsigned char *) addr)[nr >> 3] = oldval | mask;
+       return oldval & mask;
+}
+
 extern int test_and_clear_bit(int nr, volatile void * addr);
+
+static inline int __test_and_clear_bit(int nr, volatile void *addr)
+{
+       unsigned int mask = 1 << (nr & 7);
+       unsigned int oldval;
+
+       oldval = ((unsigned char *) addr)[nr >> 3];
+       ((unsigned char *) addr)[nr >> 3] = oldval & ~mask;
+       return oldval & mask;
+}
+
 extern int test_and_change_bit(int nr, volatile void * addr);
+
+static inline int __test_and_change_bit(int nr, volatile void *addr)
+{
+       unsigned int mask = 1 << (nr & 7);
+       unsigned int oldval;
+
+       oldval = ((unsigned char *) addr)[nr >> 3];
+       ((unsigned char *) addr)[nr >> 3] = oldval ^ mask;
+       return oldval & mask;
+}
+
 extern int find_first_zero_bit(void * addr, unsigned size);
 extern int find_next_zero_bit(void * addr, int size, int offset);
 
index 0c6e1911e88e9027ce4232331efb40f6bcf044f8..7d1e41733e9657ebfd862a699a84574991d6993d 100644 (file)
@@ -119,7 +119,7 @@ extern void __iounmap(void *addr);
  * is in pci.h
  */
 extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
-extern void consistent_free(void *vaddr);
+extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
 extern void consistent_sync(void *vaddr, size_t size, int rw);
 
 #define __raw_writeb(v,a)              __arch_putb(v,a)
index 744cb30601799eb9b43152a90c5016ccffb54dbf..0bf0c26f3e462fc7ac5bc377a519b19c2a985f3b 100644 (file)
@@ -41,7 +41,7 @@ extern inline void
 pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
                    dma_addr_t dma_handle)
 {
-       consistent_free(vaddr);
+       consistent_free(vaddr, size, dma_handle);
 }
 
 /* Map a single buffer of the indicated size for DMA in streaming mode.
index 1ba35108c5d48bb699460370c1210d66230f5a59..ced2af37b15930d9b88a7f282972edddf250167f 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <asm/proc-fns.h>
 
+#define vectors_base() (0)
+
 extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 {
        extern void __bad_xchg(volatile void *, int);
index becb31c2d9a8646abf26428a5e243a9463dfe3f0..77fd92b1198efe8b5c1faccd4a5d2fcf4ae4030c 100644 (file)
        "mcr    p15, 0, %0, c1, c0      @ set CR"       \
        : : "r" (x))
 
+#define CR_M   (1 << 0)        /* MMU enable                           */
+#define CR_A   (1 << 1)        /* Alignment abort enable               */
+#define CR_C   (1 << 2)        /* Dcache enable                        */
+#define CR_W   (1 << 3)        /* Write buffer enable                  */
+#define CR_P   (1 << 4)        /* 32-bit exception handler             */
+#define CR_D   (1 << 5)        /* 32-bit data address range            */
+#define CR_L   (1 << 6)        /* Implementation defined               */
+#define CD_B   (1 << 7)        /* Big endian                           */
+#define CR_S   (1 << 8)        /* System MMU protection                */
+#define CD_R   (1 << 9)        /* ROM MMU protection                   */
+#define CR_F   (1 << 10)       /* Implementation defined               */
+#define CR_Z   (1 << 11)       /* Implementation defined               */
+#define CR_I   (1 << 12)       /* Icache enable                        */
+#define CR_V   (1 << 13)       /* Vectors relocated to 0xffff0000      */
+#define CR_RR  (1 << 14)       /* Round Robin cache replacement        */
+
 extern unsigned long cr_no_alignment;  /* defined in entry-armv.S */
 extern unsigned long cr_alignment;     /* defined in entry-armv.S */
 
+#ifdef __ARM_ARCH_4__
+#define vectors_base() ((cr_alignment & CR_V) ? 0xffff0000 : 0)
+#else
+#define vectors_base() (0)
+#endif
+
 /*
  * A couple of speedups for the ARM
  */
index 70f8e6430983f1a41d33750434e7b95f05ca61aa..8da66615f301fecc23ead1fb10e0e47e2ab212b0 100644 (file)
@@ -7,27 +7,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-/*
- *  linux/include/asm-arm/xor.h
- *
- *  Copyright (C) 2001 Russell King
- *
- * 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.
- */
-
-/*
- *  linux/include/asm-arm/xor.h
- *
- *  Copyright (C) 2001 Russell King
- *
- * 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 <asm-generic/xor.h>
 
 #define __XOR(a1, a2) a1 ^= a2
@@ -160,265 +139,3 @@ static struct xor_block_template xor_block_arm4regs = {
                xor_speed(&xor_block_8regs);    \
                xor_speed(&xor_block_32regs);   \
        } while (0)
-
-#define __XOR(a1, a2) a1 ^= a2
-
-#define GET_BLOCK_2(dst) \
-       __asm__("ldmia  %0, {%1, %2}" \
-               : "=r" (dst), "=r" (a1), "=r" (a2) \
-               : "0" (dst))
-
-#define GET_BLOCK_4(dst) \
-       __asm__("ldmia  %0, {%1, %2, %3, %4}" \
-               : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
-               : "0" (dst))
-
-#define XOR_BLOCK_2(src) \
-       __asm__("ldmia  %0!, {%1, %2}" \
-               : "=r" (src), "=r" (b1), "=r" (b2) \
-               : "0" (src)); \
-       __XOR(a1, b1); __XOR(a2, b2);
-
-#define XOR_BLOCK_4(src) \
-       __asm__("ldmia  %0!, {%1, %2, %3, %4}" \
-               : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
-               : "0" (src)); \
-       __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
-
-#define PUT_BLOCK_2(dst) \
-       __asm__ __volatile__("stmia     %0!, {%2, %3}" \
-               : "=r" (dst) \
-               : "0" (dst), "r" (a1), "r" (a2))
-
-#define PUT_BLOCK_4(dst) \
-       __asm__ __volatile__("stmia     %0!, {%2, %3, %4, %5}" \
-               : "=r" (dst) \
-               : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
-
-static void
-xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 4;
-       register unsigned int a1 __asm__("r4");
-       register unsigned int a2 __asm__("r5");
-       register unsigned int a3 __asm__("r6");
-       register unsigned int a4 __asm__("r7");
-       register unsigned int b1 __asm__("r8");
-       register unsigned int b2 __asm__("r9");
-       register unsigned int b3 __asm__("ip");
-       register unsigned int b4 __asm__("lr");
-
-       do {
-               GET_BLOCK_4(p1);
-               XOR_BLOCK_4(p2);
-               PUT_BLOCK_4(p1);
-       } while (--lines);
-}
-
-static void
-xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-               unsigned long *p3)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 4;
-       register unsigned int a1 __asm__("r4");
-       register unsigned int a2 __asm__("r5");
-       register unsigned int a3 __asm__("r6");
-       register unsigned int a4 __asm__("r7");
-       register unsigned int b1 __asm__("r8");
-       register unsigned int b2 __asm__("r9");
-       register unsigned int b3 __asm__("ip");
-       register unsigned int b4 __asm__("lr");
-
-       do {
-               GET_BLOCK_4(p1);
-               XOR_BLOCK_4(p2);
-               XOR_BLOCK_4(p3);
-               PUT_BLOCK_4(p1);
-       } while (--lines);
-}
-
-static void
-xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-               unsigned long *p3, unsigned long *p4)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 2;
-       register unsigned int a1 __asm__("r8");
-       register unsigned int a2 __asm__("r9");
-       register unsigned int b1 __asm__("ip");
-       register unsigned int b2 __asm__("lr");
-
-       do {
-               GET_BLOCK_2(p1);
-               XOR_BLOCK_2(p2);
-               XOR_BLOCK_2(p3);
-               XOR_BLOCK_2(p4);
-               PUT_BLOCK_2(p1);
-       } while (--lines);
-}
-
-static void
-xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-               unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 2;
-       register unsigned int a1 __asm__("r8");
-       register unsigned int a2 __asm__("r9");
-       register unsigned int b1 __asm__("ip");
-       register unsigned int b2 __asm__("lr");
-
-       do {
-               GET_BLOCK_2(p1);
-               XOR_BLOCK_2(p2);
-               XOR_BLOCK_2(p3);
-               XOR_BLOCK_2(p4);
-               XOR_BLOCK_2(p5);
-               PUT_BLOCK_2(p1);
-       } while (--lines);
-}
-
-static struct xor_block_template xor_block_arm4regs = {
-       name:   "arm4regs",
-       do_2:   xor_arm4regs_2,
-       do_3:   xor_arm4regs_3,
-       do_4:   xor_arm4regs_4,
-       do_5:   xor_arm4regs_5,
-};
-
-#undef XOR_TRY_TEMPLATES
-#define XOR_TRY_TEMPLATES                      \
-       do {                                    \
-               xor_speed(&xor_block_arm4regs); \
-               xor_speed(&xor_block_8regs);    \
-               xor_speed(&xor_block_32regs);   \
-       } while (0)
-
-#define __XOR(a1, a2) a1 ^= a2
-
-#define GET_BLOCK_2(dst) \
-       __asm__("ldmia  %0, {%1, %2}" \
-               : "=r" (dst), "=r" (a1), "=r" (a2) \
-               : "0" (dst))
-
-#define GET_BLOCK_4(dst) \
-       __asm__("ldmia  %0, {%1, %2, %3, %4}" \
-               : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
-               : "0" (dst))
-
-#define XOR_BLOCK_2(src) \
-       __asm__("ldmia  %0!, {%1, %2}" \
-               : "=r" (src), "=r" (b1), "=r" (b2) \
-               : "0" (src)); \
-       __XOR(a1, b1); __XOR(a2, b2);
-
-#define XOR_BLOCK_4(src) \
-       __asm__("ldmia  %0!, {%1, %2, %3, %4}" \
-               : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
-               : "0" (src)); \
-       __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
-
-#define PUT_BLOCK_2(dst) \
-       __asm__ __volatile__("stmia     %0!, {%2, %3}" \
-               : "=r" (dst) \
-               : "0" (dst), "r" (a1), "r" (a2))
-
-#define PUT_BLOCK_4(dst) \
-       __asm__ __volatile__("stmia     %0!, {%2, %3, %4, %5}" \
-               : "=r" (dst) \
-               : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
-
-static void
-xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 4;
-       register unsigned int a1 __asm__("r4");
-       register unsigned int a2 __asm__("r5");
-       register unsigned int a3 __asm__("r6");
-       register unsigned int a4 __asm__("r7");
-       register unsigned int b1 __asm__("r8");
-       register unsigned int b2 __asm__("r9");
-       register unsigned int b3 __asm__("ip");
-       register unsigned int b4 __asm__("lr");
-
-       do {
-               GET_BLOCK_4(p1);
-               XOR_BLOCK_4(p2);
-               PUT_BLOCK_4(p1);
-       } while (--lines);
-}
-
-static void
-xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-               unsigned long *p3)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 4;
-       register unsigned int a1 __asm__("r4");
-       register unsigned int a2 __asm__("r5");
-       register unsigned int a3 __asm__("r6");
-       register unsigned int a4 __asm__("r7");
-       register unsigned int b1 __asm__("r8");
-       register unsigned int b2 __asm__("r9");
-       register unsigned int b3 __asm__("ip");
-       register unsigned int b4 __asm__("lr");
-
-       do {
-               GET_BLOCK_4(p1);
-               XOR_BLOCK_4(p2);
-               XOR_BLOCK_4(p3);
-               PUT_BLOCK_4(p1);
-       } while (--lines);
-}
-
-static void
-xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-               unsigned long *p3, unsigned long *p4)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 2;
-       register unsigned int a1 __asm__("r8");
-       register unsigned int a2 __asm__("r9");
-       register unsigned int b1 __asm__("ip");
-       register unsigned int b2 __asm__("lr");
-
-       do {
-               GET_BLOCK_2(p1);
-               XOR_BLOCK_2(p2);
-               XOR_BLOCK_2(p3);
-               XOR_BLOCK_2(p4);
-               PUT_BLOCK_2(p1);
-       } while (--lines);
-}
-
-static void
-xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-               unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
-       unsigned int lines = bytes / sizeof(unsigned long) / 2;
-       register unsigned int a1 __asm__("r8");
-       register unsigned int a2 __asm__("r9");
-       register unsigned int b1 __asm__("ip");
-       register unsigned int b2 __asm__("lr");
-
-       do {
-               GET_BLOCK_2(p1);
-               XOR_BLOCK_2(p2);
-               XOR_BLOCK_2(p3);
-               XOR_BLOCK_2(p4);
-               XOR_BLOCK_2(p5);
-               PUT_BLOCK_2(p1);
-       } while (--lines);
-}
-
-static struct xor_block_template xor_block_arm4regs = {
-       name:   "arm4regs",
-       do_2:   xor_arm4regs_2,
-       do_3:   xor_arm4regs_3,
-       do_4:   xor_arm4regs_4,
-       do_5:   xor_arm4regs_5,
-};
-
-#undef XOR_TRY_TEMPLATES
-#define XOR_TRY_TEMPLATES                      \
-       do {                                    \
-               xor_speed(&xor_block_arm4regs); \
-               xor_speed(&xor_block_8regs);    \
-               xor_speed(&xor_block_32regs);   \
-       } while (0)
diff --git a/include/asm-sh/bigsur.h b/include/asm-sh/bigsur.h
new file mode 100644 (file)
index 0000000..648ba21
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *
+ * Hitachi Big Sur Eval Board support
+ *
+ * Dustin McIntire (dustin@sensoria.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Derived from Hitachi SH7751 reference manual
+ * 
+ */
+
+#ifndef _ASM_BIGSUR_H_
+#define _ASM_BIGSUR_H_
+
+#include <asm/irq.h>
+#include <asm/hd64465.h>
+
+/* 7751 Internal IRQ's used by external CPLD controller */
+#define BIGSUR_IRQ_LOW 0
+#define BIGSUR_IRQ_NUM  14         /* External CPLD level 1 IRQs */
+#define BIGSUR_IRQ_HIGH (BIGSUR_IRQ_LOW + BIGSUR_IRQ_NUM)
+#define BIGSUR_2NDLVL_IRQ_LOW   (HD64465_IRQ_BASE+HD64465_IRQ_NUM)  
+#define BIGSUR_2NDLVL_IRQ_NUM   32 /* Level 2 IRQs = 4 regs * 8 bits */
+#define BIGSUR_2NDLVL_IRQ_HIGH  (BIGSUR_2NDLVL_IRQ_LOW + \
+                                 BIGSUR_2NDLVL_IRQ_NUM)
+
+/* PCI interrupt base number (A_INTA-A_INTD) */
+#define BIGSUR_SH7751_PCI_IRQ_BASE  (BIGSUR_2NDLVL_IRQ_LOW+10)  
+
+/* CPLD registers and external chip addresses */
+#define BIGSUR_HD64464_ADDR    0xB2000000
+#define BIGSUR_DGDR    0xB1FFFE00
+#define BIGSUR_BIDR    0xB1FFFD00
+#define BIGSUR_CSLR    0xB1FFFC00
+#define BIGSUR_SW1R    0xB1FFFB00
+#define BIGSUR_DBGR    0xB1FFFA00
+#define BIGSUR_BDTR    0xB1FFF900
+#define BIGSUR_BDRR    0xB1FFF800
+#define BIGSUR_PPR1    0xB1FFF700
+#define BIGSUR_PPR2    0xB1FFF600
+#define BIGSUR_IDE2    0xB1FFF500
+#define BIGSUR_IDE3    0xB1FFF400
+#define BIGSUR_SPCR    0xB1FFF300
+#define BIGSUR_ETHR    0xB1FE0000
+#define BIGSUR_PPDR    0xB1FDFF00
+#define BIGSUR_ICTL    0xB1FDFE00
+#define BIGSUR_ICMD    0xB1FDFD00
+#define BIGSUR_DMA0    0xB1FDFC00
+#define BIGSUR_DMA1    0xB1FDFB00
+#define BIGSUR_IRQ0    0xB1FDFA00
+#define BIGSUR_IRQ1    0xB1FDF900
+#define BIGSUR_IRQ2    0xB1FDF800
+#define BIGSUR_IRQ3    0xB1FDF700
+#define BIGSUR_IMR0    0xB1FDF600
+#define BIGSUR_IMR1    0xB1FDF500
+#define BIGSUR_IMR2    0xB1FDF400
+#define BIGSUR_IMR3    0xB1FDF300
+#define BIGSUR_IRLMR0  0xB1FDF200
+#define BIGSUR_IRLMR1  0xB1FDF100
+#define BIGSUR_V320USC_ADDR  0xB1000000
+#define BIGSUR_HD64465_ADDR  0xB0000000
+#define BIGSUR_INTERNAL_BASE 0xB0000000
+
+/* SMC ethernet card parameters */
+#define BIGSUR_ETHER_IOPORT            0x220
+
+/* IDE register paramters */
+#define BIGSUR_IDECMD_IOPORT   0x1f0
+#define BIGSUR_IDECTL_IOPORT   0x1f8
+
+/* LED bit position in BIGSUR_CSLR */
+#define BIGSUR_LED  (1<<4)
+
+/* PCI: default LOCAL memory window sizes (seen from PCI bus) */
+#define BIGSUR_LSR0_SIZE    (64*(1<<20)) //64MB
+#define BIGSUR_LSR1_SIZE    (64*(1<<20)) //64MB
+
+#endif /* _ASM_BIGSUR_H_ */
index d74bd4fbf0467649c18631d6e74b3c65c7c189b8..a897f7bdd4ee944b6f8f2d98c2ced89653333869 100644 (file)
@@ -19,6 +19,16 @@ static __inline__ void set_bit(int nr, volatile void * addr)
        restore_flags(flags);
 }
 
+static __inline__ void __set_bit(int nr, volatile void * addr)
+{
+       int     mask;
+       volatile unsigned int *a = addr;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       *a |= mask;
+}
+
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
@@ -37,6 +47,16 @@ static __inline__ void clear_bit(int nr, volatile void * addr)
        restore_flags(flags);
 }
 
+static __inline__ void __clear_bit(int nr, volatile void * addr)
+{
+       int     mask;
+       volatile unsigned int *a = addr;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       *a &= ~mask;
+}
+
 static __inline__ void change_bit(int nr, volatile void * addr)
 {
        int     mask;
@@ -50,6 +70,16 @@ static __inline__ void change_bit(int nr, volatile void * addr)
        restore_flags(flags);
 }
 
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+       int     mask;
+       volatile unsigned int *a = addr;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       *a ^= mask;
+}
+
 static __inline__ int test_and_set_bit(int nr, volatile void * addr)
 {
        int     mask, retval;
@@ -66,6 +96,19 @@ static __inline__ int test_and_set_bit(int nr, volatile void * addr)
        return retval;
 }
 
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+       int     mask, retval;
+       volatile unsigned int *a = addr;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       retval = (mask & *a) != 0;
+       *a |= mask;
+
+       return retval;
+}
+
 static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 {
        int     mask, retval;
@@ -82,6 +125,19 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
        return retval;
 }
 
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+       int     mask, retval;
+       volatile unsigned int *a = addr;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       retval = (mask & *a) != 0;
+       *a &= ~mask;
+
+       return retval;
+}
+
 static __inline__ int test_and_change_bit(int nr, volatile void * addr)
 {
        int     mask, retval;
@@ -98,6 +154,18 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr)
        return retval;
 }
 
+static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
+{
+       int     mask, retval;
+       volatile unsigned int *a = addr;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       retval = (mask & *a) != 0;
+       *a ^= mask;
+
+       return retval;
+}
 
 static __inline__ int test_bit(int nr, const volatile void *addr)
 {
@@ -157,6 +225,23 @@ found_middle:
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #ifdef __LITTLE_ENDIAN__
 #define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
 #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr))
index 4b12f4b1bf0a66e712f331c1cc4dd4605cc2287c..c006ab7991e2e2e8ba592ca7550a9a109164f0cc 100644 (file)
@@ -32,7 +32,7 @@ static void __init check_bugs(void)
                break;
        case CPU_SH7750:
                *p++ = '4';
-               printk("CPU: SH7750\n");
+               printk("CPU: SH7750/SH7751\n");
                break;
        case CPU_ST40STB1:
                *p++ = '4';
diff --git a/include/asm-sh/dc_sysasic.h b/include/asm-sh/dc_sysasic.h
new file mode 100644 (file)
index 0000000..b1a9749
--- /dev/null
@@ -0,0 +1,35 @@
+/* include/asm-sh/dc_sysasic.h
+ *
+ * Definitions for the Dreamcast System ASIC and related peripherals.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#include <asm/irq.h>
+
+/* Hardware events -
+
+   Each of these events correspond to a bit within the Event Mask Registers/
+   Event Status Registers.  Because of the virtual IRQ numbering scheme, a
+   base offset must be used when calculating the virtual IRQ that each event
+   takes.
+*/
+
+#define HW_EVENT_IRQ_BASE  OFFCHIP_IRQ_BASE /* 48 */
+
+/* IRQ 13 */
+#define HW_EVENT_VSYNC     (HW_EVENT_IRQ_BASE +  5) /* VSync */
+#define HW_EVENT_MAPLE_DMA (HW_EVENT_IRQ_BASE + 12) /* Maple DMA complete */
+#define HW_EVENT_GDROM_DMA (HW_EVENT_IRQ_BASE + 14) /* GD-ROM DMA complete */
+
+/* IRQ 11 */
+#define HW_EVENT_GDROM_CMD (HW_EVENT_IRQ_BASE + 32) /* GD-ROM cmd. complete */
+#define HW_EVENT_AICA_SYS  (HW_EVENT_IRQ_BASE + 33) /* AICA-related */
+#define HW_EVENT_EXTERNAL  (HW_EVENT_IRQ_BASE + 35) /* Ext. (expansion) */
+
+#define HW_EVENT_IRQ_MAX (HW_EVENT_IRQ_BASE + 95)
index cfb53de784f05686570dfd0239a3b0cfdf5aa568..457ea6b94e66352e4df33b4e22f1856476314ec6 100644 (file)
@@ -6,8 +6,7 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-       unsigned int __softirq_active;
-       unsigned int __softirq_mask;
+       unsigned int __softirq_pending;
        unsigned int __local_irq_count;
        unsigned int __local_bh_count;
        unsigned int __syscall_count;
index 51a10f25380d0b415c37d62a9a48a46a0a7b487c..b2eac9240cbc3ac64e26dd8f5982fa1977316224 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ASM_SH_HD64465_GPIO_
 #define _ASM_SH_HD64465_GPIO_ 1
 /*
- * $Id: hd64465_gpio.h,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * $Id: hd64465_gpio.h,v 1.2 2001/05/24 00:14:13 gniibe Exp $
  *
  * Hitachi HD64465 companion chip: General Purpose IO pins support.
  * This layer enables other device drivers to configure GPIO
index 9eea1f5bcf1e892895db08fd4877ce1061ce8768..c6602cf6b30975a07fdb0de27201bbc0c9c434e0 100644 (file)
 
 # if defined(CONFIG_SH_HP600)
 #  include <asm/io_hd64461.h>
-# elif defined(CONFIG_SH_7750_OVERDRIVE)
-#  include <asm/io_od.h>
-# elif defined(CONFIG_SH_SOLUTION_ENGINE)
+# elif (defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7751_SOLUTION_ENGINE))
 #  include <asm/io_se.h>
+# elif defined(CONFIG_SH_SH2000)
+#  include <asm/io_sh2000.h>
 # elif defined(CONFIG_SH_DMIDA) || \
        defined(CONFIG_SH_STB1_HARP) || \
        defined(CONFIG_SH_STB1_OVERDRIVE)
 #  include <asm/io_dc.h>
 # elif defined(CONFIG_SH_CAT68701)
 #  include <asm/io_cat68701.h>
+# elif defined(CONFIG_SH_BIGSUR)
+#  include <asm/io_bigsur.h>
 # elif defined(CONFIG_SH_UNKNOWN)
 #  include <asm/io_unknown.h>
 # else
diff --git a/include/asm-sh/io_bigsur.h b/include/asm-sh/io_bigsur.h
new file mode 100644 (file)
index 0000000..1795f71
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * include/asm-sh/io_bigsur.h
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc. 
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#ifndef _ASM_SH_IO_BIGSUR_H
+#define _ASM_SH_IO_BIGSUR_H
+
+#include <linux/types.h>
+#include <asm/io_generic.h>
+
+extern unsigned char bigsur_inb(unsigned long port);
+extern unsigned short bigsur_inw(unsigned long port);
+extern unsigned int bigsur_inl(unsigned long port);
+
+extern void bigsur_outb(unsigned char value, unsigned long port);
+extern void bigsur_outw(unsigned short value, unsigned long port);
+extern void bigsur_outl(unsigned int value, unsigned long port);
+
+extern unsigned char bigsur_inb_p(unsigned long port);
+extern void bigsur_outb_p(unsigned char value, unsigned long port);
+
+extern void bigsur_insb(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_insw(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_insl(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void bigsur_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void bigsur_outsl(unsigned long port, const void *addr, unsigned long count);
+extern unsigned long bigsur_isa_port2addr(unsigned long offset);
+extern int bigsur_irq_demux(int irq);
+extern void bigsur_init_pci(void);
+/* Provision for generic secondary demux step -- used by PCMCIA code */
+extern void bigsur_register_irq_demux(int irq,
+               int (*demux)(int irq, void *dev), void *dev);
+extern void bigsur_unregister_irq_demux(int irq);
+/* Set this variable to 1 to see port traffic */
+extern int bigsur_io_debug;
+/* Map a range of ports to a range of kernel virtual memory. */
+extern void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift);
+extern void bigsur_port_unmap(u32 baseport, u32 nports);
+
+#endif /* _ASM_SH_IO_BIGSUR_H */
+
+#ifdef __WANT_IO_DEF
+
+# define __inb                 bigsur_inb
+# define __inw                 bigsur_inw
+# define __inl                 bigsur_inl
+# define __outb                        bigsur_outb
+# define __outw                        bigsur_outw
+# define __outl                        bigsur_outl
+
+# define __inb_p               bigsur_inb_p
+# define __inw_p               bigsur_inw
+# define __inl_p               bigsur_inl
+# define __outb_p              bigsur_outb_p
+# define __outw_p              bigsur_outw
+# define __outl_p              bigsur_outl
+
+# define __insb                        bigsur_insb
+# define __insw                        bigsur_insw
+# define __insl                        bigsur_insl
+# define __outsb               bigsur_outsb
+# define __outsw               bigsur_outsw
+# define __outsl               bigsur_outsl
+
+# define __readb               generic_readb
+# define __readw               generic_readw
+# define __readl               generic_readl
+# define __writeb              generic_writeb
+# define __writew              generic_writew
+# define __writel              generic_writel
+
+# define __isa_port2addr       bigsur_isa_port2addr
+# define __ioremap             generic_ioremap
+# define __iounmap             generic_iounmap
+
+#endif
diff --git a/include/asm-sh/io_od.h b/include/asm-sh/io_od.h
deleted file mode 100644 (file)
index a0722d8..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * include/asm-sh/io_od.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for an STMicroelectronics Overdrive
- */
-
-#ifndef _ASM_SH_IO_OD_H
-#define _ASM_SH_IO_OD_H
-
-#include <asm/io_generic.h>
-
-extern unsigned char od_inb(unsigned long port);
-extern unsigned short od_inw(unsigned long port);
-extern unsigned int od_inl(unsigned long port);
-
-extern void od_outb(unsigned char value, unsigned long port);
-extern void od_outw(unsigned short value, unsigned long port);
-extern void od_outl(unsigned int value, unsigned long port);
-
-extern unsigned char od_inb_p(unsigned long port);
-extern unsigned short od_inw_p(unsigned long port);
-extern unsigned int od_inl_p(unsigned long port);
-extern void od_outb_p(unsigned char value, unsigned long port);
-extern void od_outw_p(unsigned short value, unsigned long port);
-extern void od_outl_p(unsigned int value, unsigned long port);
-
-extern void od_insb(unsigned long port, void *addr, unsigned long count);
-extern void od_insw(unsigned long port, void *addr, unsigned long count);
-extern void od_insl(unsigned long port, void *addr, unsigned long count);
-extern void od_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long od_isa_port2addr(unsigned long offset);
-
-#ifdef __WANT_IO_DEF
-
-# define __inb                 od_inb
-# define __inw                 od_inw
-# define __inl                 od_inl
-# define __outb                        od_outb
-# define __outw                        od_outw
-# define __outl                        od_outl
-
-# define __inb_p               od_inb_p
-# define __inw_p               od_inw_p
-# define __inl_p               od_inl_p
-# define __outb_p              od_outb_p
-# define __outw_p              od_outw_p
-# define __outl_p              od_outl_p
-
-# define __insb                        od_insb
-# define __insw                        od_insw
-# define __insl                        od_insl
-# define __outsb               od_outsb
-# define __outsw               od_outsw
-# define __outsl               od_outsl
-
-# define __readb               generic_readb
-# define __readw               generic_readw
-# define __readl               generic_readl
-# define __writeb              generic_writeb
-# define __writew              generic_writew
-# define __writel              generic_writel
-
-# define __isa_port2addr       od_isa_port2addr
-# define __ioremap             generic_ioremap
-# define __iounmap             generic_iounmap
-
-#endif
-
-#endif /* _ASM_SH_IO_OD_H */
diff --git a/include/asm-sh/io_sh2000.h b/include/asm-sh/io_sh2000.h
new file mode 100644 (file)
index 0000000..9152cef
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * include/asm-sh/io_sh2000.h
+ *
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *           2001 SUGIOKA Toshinobu (sugioka@itonet.co.jp)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for use when we don't know what machine we are on
+ */
+
+#ifndef _ASM_SH_IO_SH2000_H
+#define _ASM_SH_IO_SH2000_H
+
+#include <asm/io_generic.h>
+
+unsigned long sh2000_isa_port2addr(unsigned long offset);
+
+#ifdef __WANT_IO_DEF
+
+# define __inb                 generic_inb
+# define __inw                 generic_inw
+# define __inl                 generic_inl
+# define __outb                        generic_outb
+# define __outw                        generic_outw
+# define __outl                        generic_outl
+
+# define __inb_p               generic_inb_p
+# define __inw_p               generic_inw
+# define __inl_p               generic_inl
+# define __outb_p              generic_outb_p
+# define __outw_p              generic_outw
+# define __outl_p              generic_outl
+
+# define __insb                        generic_insb
+# define __insw                        generic_insw
+# define __insl                        generic_insl
+# define __outsb               generic_outsb
+# define __outsw               generic_outsw
+# define __outsl               generic_outsl
+
+# define __readb               generic_readb
+# define __readw               generic_readw
+# define __readl               generic_readl
+# define __writeb              generic_writeb
+# define __writew              generic_writew
+# define __writel              generic_writel
+
+# define __isa_port2addr       sh2000_isa_port2addr
+# define __ioremap             generic_ioremap
+# define __iounmap             generic_iounmap
+
+#endif
+
+#endif /* _ASM_SH_IO_SH2000_H */
index 140eeb7e656ad4571be96985f93655a13037d705..94abf1177e14eeff52eb9ba43dede63d48caddfa 100644 (file)
@@ -43,7 +43,8 @@
 #define DMA_PRIORITY   7
 
 #if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750)
+    defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) || \
+    defined (CONFIG_CPU_SUBTYPE_SH7751)
 #define SCI_ERI_IRQ    23
 #define SCI_RXI_IRQ    24
 #define SCI_TXI_IRQ    25
@@ -68,7 +69,8 @@
 #define IRDA_IPR_ADDR  INTC_IPRE
 #define IRDA_IPR_POS   2
 #define IRDA_PRIORITY  3
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+      defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 #define SCIF_ERI_IRQ   40
 #define SCIF_RXI_IRQ   41
 #define SCIF_BRI_IRQ   42
@@ -95,7 +97,7 @@
 
 /* 1. ONCHIP_NR_IRQS */
 #ifdef CONFIG_SH_GENERIC
-# define ONCHIP_NR_IRQS 89
+# define ONCHIP_NR_IRQS 144
 #else
 # if defined(CONFIG_CPU_SUBTYPE_SH7707)
 #  define ONCHIP_NR_IRQS 64
 #  define PINT_NR_IRQS   16
 # elif defined(CONFIG_CPU_SUBTYPE_SH7750)
 #  define ONCHIP_NR_IRQS 48    // Actually 44
+# elif defined(CONFIG_CPU_SUBTYPE_SH7751)
+#  define ONCHIP_NR_IRQS 72
 # elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
-#  define ONCHIP_NR_IRQS 89
+#  define ONCHIP_NR_IRQS 144
 # endif
 #endif
 
 #else
 # if defined(CONFIG_HD64461)
 #  define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_BIGSUR) /* must be before CONFIG_HD64465 */
+#  define OFFCHIP_NR_IRQS 48
 # elif defined(CONFIG_HD64465)
 #  define OFFCHIP_NR_IRQS 16
 # elif defined (CONFIG_SH_EC3104)
 #  define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_DREAMCAST)
+#  define OFFCHIP_NR_IRQS 96
 # else
 #  define OFFCHIP_NR_IRQS 0
 # endif
@@ -240,6 +248,16 @@ extern int ipr_irq_demux(int irq);
 #define __irq_demux(irq) irq
 #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+    defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#define INTC_ICR        0xffd00000
+#define INTC_ICR_NMIL  (1<<15)
+#define INTC_ICR_MAI   (1<<14)
+#define INTC_ICR_NMIB  (1<<9)
+#define INTC_ICR_NMIE  (1<<8)
+#define INTC_ICR_IRLM  (1<<7)
+#endif
+
 #ifdef CONFIG_CPU_SUBTYPE_ST40STB1
 #define INTC2_FIRST_IRQ 64
 #define NR_INTC2_IRQS 25
@@ -266,6 +284,11 @@ extern __inline__ int irq_demux(int irq) {
        return __irq_demux(irq);
 }
 
+#elif defined(CONFIG_SH_BIGSUR)
+
+extern int bigsur_irq_demux(int irq);
+#define irq_demux(irq) bigsur_irq_demux(irq)
+
 #elif defined(CONFIG_HD64461)
 
 extern int hd64461_irq_demux(int irq);
@@ -286,6 +309,11 @@ extern int ec3104_irq_demux(int irq);
 extern int cat68701_irq_demux(int irq);
 #define irq_demux cat68701_irq_demux
 
+#elif defined(CONFIG_SH_DREAMCAST)
+
+extern int systemasic_irq_demux(int irq);
+#define irq_demux systemasic_irq_demux
+
 #else
 
 #define irq_demux(irq) __irq_demux(irq)
index 8216c947bea2d5ae48c3cef5232f555f7780d194..f988bef6af2663ed1e49be317438a00264f29e1d 100644 (file)
@@ -72,8 +72,10 @@ struct sh_machine_vector
        unsigned int mv_hw_hp680 : 1;
        unsigned int mv_hw_hp690 : 1;
        unsigned int mv_hw_hd64461 : 1;
+       unsigned int mv_hw_sh2000 : 1;
        unsigned int mv_hw_hd64465 : 1;
        unsigned int mv_hw_dreamcast : 1;
+       unsigned int mv_hw_bigsur : 1;
 };
 
 extern struct sh_machine_vector sh_mv;
@@ -87,9 +89,12 @@ extern struct sh_machine_vector sh_mv;
 #define MACH_HP690     (sh_mv.mv_hw_hp690)
 #define MACH_HD64461   (sh_mv.mv_hw_hd64461)
 #define MACH_HD64465   (sh_mv.mv_hw_hd64465)
+#define MACH_SH2000    (sh_mv.mv_hw_sh2000)
 #define MACH_DREAMCAST (sh_mv.mv_hw_dreamcast)
+#define MACH_BIGSUR    (sh_mv.mv_hw_bigsur)
 #else
-# ifdef CONFIG_SH_SOLUTION_ENGINE
+# if defined(CONFIG_SH_SOLUTION_ENGINE) || \
+     defined(CONFIG_SH_7751_SOLUTION_ENGINE)
 #  define MACH_SE              1
 # else
 #  define MACH_SE              0
@@ -114,6 +119,7 @@ extern struct sh_machine_vector sh_mv;
 # else
 #  define MACH_HP690           0
 # endif
+# endif
 # ifdef CONFIG_HD64461
 #  define MACH_HD64461         1
 # else
@@ -124,6 +130,11 @@ extern struct sh_machine_vector sh_mv;
 # else
 #  define MACH_HD64465         0
 # endif
+# ifdef CONFIG_SH_SH2000
+#  define MACH_SH2000          1
+# else
+#  define MACH_SH2000          0
+# endif
 # ifdef CONFIG_SH_EC3104
 #  define MACH_EC3104          1
 # else
@@ -134,6 +145,10 @@ extern struct sh_machine_vector sh_mv;
 # else
 #  define MACH_DREAMCAST       0
 # endif
+# ifdef CONFIG_SH_BIGSUR
+#  define MACH_BIGSUR          1
+# else
+#  define MACH_BIGSUR          0
 #endif
 
 #endif /* _ASM_SH_MACHVEC_H */
diff --git a/include/asm-sh/mc146818rtc.h b/include/asm-sh/mc146818rtc.h
new file mode 100644 (file)
index 0000000..3172034
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <asm/rtc.h>
+
+#define RTC_ALWAYS_BCD 1
+
+/* FIXME:RTC Interrupt feature is not implemented yet. */
+#undef  RTC_IRQ
+#define RTC_IRQ                0
+
+#if defined(__sh3__)
+#define RTC_PORT(n)            (R64CNT+(n)*2)
+#define CMOS_READ(addr)                __CMOS_READ(addr,b)
+#define CMOS_WRITE(val,addr)   __CMOS_WRITE(val,addr,b)
+
+#elif defined(__SH4__)
+#define RTC_PORT(n)            (R64CNT+(n)*4)
+#define CMOS_READ(addr)                __CMOS_READ(addr,w)
+#define CMOS_WRITE(val,addr)   __CMOS_WRITE(val,addr,w)
+#endif
+
+#define __CMOS_READ(addr, s) ({                                                \
+       unsigned char val=0, rcr1, rcr2, r64cnt, retry;                 \
+       switch(addr) {                                                  \
+               case RTC_SECONDS:                                       \
+                       val = ctrl_inb(RSECCNT);                        \
+                       break;                                          \
+               case RTC_SECONDS_ALARM:                                 \
+                       val = ctrl_inb(RSECAR);                         \
+                       break;                                          \
+               case RTC_MINUTES:                                       \
+                       val = ctrl_inb(RMINCNT);                        \
+                       break;                                          \
+               case RTC_MINUTES_ALARM:                                 \
+                       val = ctrl_inb(RMINAR);                         \
+                       break;                                          \
+               case RTC_HOURS:                                         \
+                       val = ctrl_inb(RHRCNT);                         \
+                       break;                                          \
+               case RTC_HOURS_ALARM:                                   \
+                       val = ctrl_inb(RHRAR);                          \
+                       break;                                          \
+               case RTC_DAY_OF_WEEK:                                   \
+                       val = ctrl_inb(RWKCNT);                         \
+                       break;                                          \
+               case RTC_DAY_OF_MONTH:                                  \
+                       val = ctrl_inb(RDAYCNT);                        \
+                       break;                                          \
+               case RTC_MONTH:                                         \
+                       val = ctrl_inb(RMONCNT);                        \
+                       break;                                          \
+               case RTC_YEAR:                                          \
+                       val = ctrl_in##s(RYRCNT);                       \
+                       break;                                          \
+               case RTC_REG_A: /* RTC_FREQ_SELECT */                   \
+                       rcr2 = ctrl_inb(RCR2);                          \
+                       val = (rcr2 & RCR2_PESMASK) >> 4;               \
+                       rcr1 = ctrl_inb(RCR1);                          \
+                       rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\
+                       retry = 0;                                      \
+                       do {                                            \
+                               ctrl_outb(rcr1, RCR1); /* clear CF */   \
+                               r64cnt = ctrl_inb(R64CNT);              \
+                       } while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\
+                       r64cnt ^= RTC_BIT_INVERTED;                     \
+                       if(r64cnt == 0x7f || r64cnt == 0)               \
+                               val |= RTC_UIP;                         \
+                       break;                                          \
+               case RTC_REG_B: /* RTC_CONTROL */                       \
+                       rcr1 = ctrl_inb(RCR1);                          \
+                       rcr2 = ctrl_inb(RCR2);                          \
+                       if(rcr1 & RCR1_CIE)     val |= RTC_UIE;         \
+                       if(rcr1 & RCR1_AIE)     val |= RTC_AIE;         \
+                       if(rcr2 & RCR2_PESMASK) val |= RTC_PIE;         \
+                       if(!(rcr2 & RCR2_START))val |= RTC_SET;         \
+                       val |= RTC_24H;                                 \
+                       break;                                          \
+               case RTC_REG_C: /* RTC_INTR_FLAGS */                    \
+                       rcr1 = ctrl_inb(RCR1);                          \
+                       rcr1 &= ~(RCR1_CF | RCR1_AF);                   \
+                       ctrl_outb(rcr1, RCR1);                          \
+                       rcr2 = ctrl_inb(RCR2);                          \
+                       rcr2 &= ~RCR2_PEF;                              \
+                       ctrl_outb(rcr2, RCR2);                          \
+                       break;                                          \
+               case RTC_REG_D: /* RTC_VALID */                         \
+                       /* Always valid ... */                          \
+                       val = RTC_VRT;                                  \
+                       break;                                          \
+               default:                                                \
+                       break;                                          \
+       }                                                               \
+       val;                                                            \
+})
+
+#define __CMOS_WRITE(val, addr, s) ({                                  \
+       unsigned char rcr1,rcr2;                                        \
+       switch(addr) {                                                  \
+               case RTC_SECONDS:                                       \
+                       ctrl_outb(val, RSECCNT);                        \
+                       break;                                          \
+               case RTC_SECONDS_ALARM:                                 \
+                       ctrl_outb(val, RSECAR);                         \
+                       break;                                          \
+               case RTC_MINUTES:                                       \
+                       ctrl_outb(val, RMINCNT);                        \
+                       break;                                          \
+               case RTC_MINUTES_ALARM:                                 \
+                       ctrl_outb(val, RMINAR);                         \
+                       break;                                          \
+               case RTC_HOURS:                                         \
+                       ctrl_outb(val, RHRCNT);                         \
+                       break;                                          \
+               case RTC_HOURS_ALARM:                                   \
+                       ctrl_outb(val, RHRAR);                          \
+                       break;                                          \
+               case RTC_DAY_OF_WEEK:                                   \
+                       ctrl_outb(val, RWKCNT);                         \
+                       break;                                          \
+               case RTC_DAY_OF_MONTH:                                  \
+                       ctrl_outb(val, RDAYCNT);                        \
+                       break;                                          \
+               case RTC_MONTH:                                         \
+                       ctrl_outb(val, RMONCNT);                        \
+                       break;                                          \
+               case RTC_YEAR:                                          \
+                       ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\
+                       break;                                          \
+               case RTC_REG_A: /* RTC_FREQ_SELECT */                   \
+                       rcr2 = ctrl_inb(RCR2);                          \
+                       if((val & RTC_DIV_CTL) == RTC_DIV_RESET2)       \
+                               rcr2 |= RCR2_RESET;                     \
+                       ctrl_outb(rcr2, RCR2);                          \
+                       break;                                          \
+               case RTC_REG_B: /* RTC_CONTROL */                       \
+                       rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF;       \
+                       if(val & RTC_AIE) rcr1 |= RCR1_AIE;             \
+                       else              rcr1 &= ~RCR1_AIE;            \
+                       if(val & RTC_UIE) rcr1 |= RCR1_CIE;             \
+                       else              rcr1 &= ~RCR1_CIE;            \
+                       ctrl_outb(rcr1, RCR1);                          \
+                       rcr2 = ctrl_inb(RCR2);                          \
+                       if(val & RTC_SET) rcr2 &= ~RCR2_START;          \
+                       else              rcr2 |= RCR2_START;           \
+                       ctrl_outb(rcr2, RCR2);                          \
+                       break;                                          \
+               case RTC_REG_C: /* RTC_INTR_FLAGS */                    \
+                       break;                                          \
+               case RTC_REG_D: /* RTC_VALID */                         \
+                       break;                                          \
+               default:                                                \
+                       break;                                          \
+       }                                                               \
+})
+#endif /* _ASM_MC146818RTC_H */
diff --git a/include/asm-sh/pci-sh7751.h b/include/asm-sh/pci-sh7751.h
new file mode 100644 (file)
index 0000000..ff8c6aa
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ *     Low-Level PCI Support for SH7751 targets
+ *
+ *  Dustin McIntire (dustin@sensoria.com) (c) 2001
+ *     
+ *  May be copied or modified under the terms of the GNU General Public
+ *  License.  See linux/COPYING for more information.
+ *
+ */
+
+#ifndef _PCI_SH7751_H_
+#define _PCI_SH7751_H_
+
+#include <linux/pci.h>
+
+/* set debug level 4=verbose...1=terse */
+//#define DEBUG_PCI 3
+#undef DEBUG_PCI
+
+#ifdef DEBUG_PCI
+#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); }
+#else
+#define PCIDBG(n, x...)
+#endif
+
+/* startup values */
+#define PCI_PROBE_BIOS 1
+#define PCI_PROBE_CONF1 2
+#define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+#define PCI_NO_CHECKS 0x400
+#define PCI_ASSIGN_ROMS 0x1000
+#define PCI_BIOS_IRQ_SCAN 0x2000
+
+/* Platform Specific Values */
+#define SH7751_VENDOR_ID             0x1054
+#define SH7751_DEVICE_ID             0x3505
+
+/* SH7751 Specific Values */
+#define SH7751_PCI_CONFIG_BASE      0xFD000000  /* Config space base addr */
+#define SH7751_PCI_CONFIG_SIZE       0x1000000   /* Config space size */
+#define SH7751_PCI_MEMORY_BASE      0xFD000000  /* Memory space base addr */
+#define SH7751_PCI_MEM_SIZE          0x01000000  /* Size of Memory window */
+#define SH7751_PCI_IO_BASE           0xFE240000  /* IO space base address */
+#define SH7751_PCI_IO_SIZE           0x40000     /* Size of IO window */
+
+#define SH7751_PCIREG_BASE           0xFE200000  /* PCI regs base address */
+#define PCI_REG(n)                  (SH7751_PCIREG_BASE+ n)
+
+#define SH7751_PCICONF0            0x0           /* PCI Config Reg 0 */
+  #define SH7751_PCICONF0_DEVID      0xFFFF0000  /* Device ID */
+  #define SH7751_PCICONF0_VNDID      0x0000FFFF  /* Vendor ID */
+#define SH7751_PCICONF1            0x4           /* PCI Config Reg 1 */
+  #define SH7751_PCICONF1_DPE        0x80000000  /* Data Parity Error */
+  #define SH7751_PCICONF1_SSE        0x40000000  /* System Error Status */
+  #define SH7751_PCICONF1_RMA        0x20000000  /* Master Abort */
+  #define SH7751_PCICONF1_RTA        0x10000000  /* Target Abort Rx Status */
+  #define SH7751_PCICONF1_STA        0x08000000  /* Target Abort Exec Status */
+  #define SH7751_PCICONF1_DEV        0x06000000  /* Timing Status */
+  #define SH7751_PCICONF1_DPD        0x01000000  /* Data Parity Status */
+  #define SH7751_PCICONF1_FBBC       0x00800000  /* Back 2 Back Status */
+  #define SH7751_PCICONF1_UDF        0x00400000  /* User Defined Status */
+  #define SH7751_PCICONF1_66M        0x00200000  /* 66Mhz Operation Status */
+  #define SH7751_PCICONF1_PM         0x00100000  /* Power Management Status */
+  #define SH7751_PCICONF1_PBBE       0x00000200  /* Back 2 Back Control */
+  #define SH7751_PCICONF1_SER        0x00000100  /* SERR Output Control */
+  #define SH7751_PCICONF1_WCC        0x00000080  /* Wait Cycle Control */
+  #define SH7751_PCICONF1_PER        0x00000040  /* Parity Error Response */
+  #define SH7751_PCICONF1_VPS        0x00000020  /* VGA Pallet Snoop */
+  #define SH7751_PCICONF1_MWIE       0x00000010  /* Memory Write+Invalidate */
+  #define SH7751_PCICONF1_SPC        0x00000008  /* Special Cycle Control */
+  #define SH7751_PCICONF1_BUM        0x00000004  /* Bus Master Control */
+  #define SH7751_PCICONF1_MES        0x00000002  /* Memory Space Control */
+  #define SH7751_PCICONF1_IOS        0x00000001  /* I/O Space Control */
+#define SH7751_PCICONF2            0x8           /* PCI Config Reg 2 */
+  #define SH7751_PCICONF2_BCC        0xFF000000  /* Base Class Code */
+  #define SH7751_PCICONF2_SCC        0x00FF0000  /* Sub-Class Code */
+  #define SH7751_PCICONF2_RLPI       0x0000FF00  /* Programming Interface */
+  #define SH7751_PCICONF2_REV        0x000000FF  /* Revision ID */
+#define SH7751_PCICONF3            0xC           /* PCI Config Reg 3 */ 
+  #define SH7751_PCICONF3_BIST7      0x80000000  /* Bist Supported */
+  #define SH7751_PCICONF3_BIST6      0x40000000  /* Bist Executing */
+  #define SH7751_PCICONF3_BIST3_0    0x0F000000  /* Bist Passed */
+  #define SH7751_PCICONF3_HD7        0x00800000  /* Single Funtion device */
+  #define SH7751_PCICONF3_HD6_0      0x007F0000  /* Configuration Layout */
+  #define SH7751_PCICONF3_LAT        0x0000FF00  /* Latency Timer */
+  #define SH7751_PCICONF3_CLS        0x000000FF  /* Cache Line Size */
+#define SH7751_PCICONF4            0x10          /* PCI Config Reg 4 */
+  #define SH7751_PCICONF4_BASE       0xFFFFFFFC  /* I/O Space Base Addr */
+  #define SH7751_PCICONF4_ASI        0x00000001  /* Address Space Type */
+#define SH7751_PCICONF5            0x14          /* PCI Config Reg 5 */
+  #define SH7751_PCICONF5_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
+  #define SH7751_PCICONF5_LAP        0x00000008  /* Prefetch Enabled */
+  #define SH7751_PCICONF5_LAT        0x00000006  /* Local Memory type */
+  #define SH7751_PCICONF5_ASI        0x00000001  /* Address Space Type */  
+#define SH7751_PCICONF6            0x18          /* PCI Config Reg 6 */
+  #define SH7751_PCICONF6_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
+  #define SH7751_PCICONF6_LAP        0x00000008  /* Prefetch Enabled */
+  #define SH7751_PCICONF6_LAT        0x00000006  /* Local Memory type */
+  #define SH7751_PCICONF6_ASI        0x00000001  /* Address Space Type */  
+/* PCICONF7 - PCICONF10 are undefined */
+#define SH7751_PCICONF11           0x2C          /* PCI Config Reg 11 */
+  #define SH7751_PCICONF11_SSID      0xFFFF0000  /* Subsystem ID */
+  #define SH7751_PCICONF11_SVID      0x0000FFFF  /* Subsystem Vendor ID */
+/* PCICONF12 is undefined */
+#define SH7751_PCICONF13           0x34          /* PCI Config Reg 13 */
+  #define SH7751_PCICONF13_CPTR      0x000000FF  /* PM function pointer */
+/* PCICONF14 is undefined */
+#define SH7751_PCICONF15           0x3C          /* PCI Config Reg 15 */
+  #define SH7751_PCICONF15_IPIN      0x000000FF  /* Interrupt Pin */
+#define SH7751_PCICONF16           0x40          /* PCI Config Reg 16 */
+  #define SH7751_PCICONF16_PMES      0xF8000000  /* PME Support */
+  #define SH7751_PCICONF16_D2S       0x04000000  /* D2 Support */
+  #define SH7751_PCICONF16_D1S       0x02000000  /* D1 Support */
+  #define SH7751_PCICONF16_DSI       0x00200000  /* Bit Device Init. */
+  #define SH7751_PCICONF16_PMCK      0x00080000  /* Clock for PME req. */
+  #define SH7751_PCICONF16_VER       0x00070000  /* PM Version */
+  #define SH7751_PCICONF16_NIP       0x0000FF00  /* Next Item Pointer */
+  #define SH7751_PCICONF16_CID       0x000000FF  /* Capability Identifier */
+#define SH7751_PCICONF17           0x44          /* PCI Config Reg 17 */
+  #define SH7751_PCICONF17_DATA      0xFF000000  /* Data field for PM */
+  #define SH7751_PCICONF17_PMES      0x00800000  /* PME Status */
+  #define SH7751_PCICONF17_DSCL      0x00600000  /* Data Scaling Value */
+  #define SH7751_PCICONF17_DSEL      0x001E0000  /* Data Select */
+  #define SH7751_PCICONF17_PMEN      0x00010000  /* PME Enable */
+  #define SH7751_PCICONF17_PWST      0x00000003  /* Power State */
+/* SH7715 Internal PCI Registers */
+#define SH7751_PCICR               0x100         /* PCI Control Register */
+  #define SH7751_PCICR_PREFIX        0xA5000000  /* CR prefix for write */
+  #define SH7751_PCICR_TRSB          0x00000200  /* Target Read Single */
+  #define SH7751_PCICR_BSWP          0x00000100  /* Target Byte Swap */
+  #define SH7751_PCICR_PLUP          0x00000080  /* Enable PCI Pullup */
+  #define SH7751_PCICR_ARBM          0x00000040  /* PCI Arbitration Mode */
+  #define SH7751_PCICR_MD            0x00000030  /* MD9 and MD10 status */
+  #define SH7751_PCICR_SERR          0x00000008  /* SERR output assert */
+  #define SH7751_PCICR_INTA          0x00000004  /* INTA output assert */
+  #define SH7751_PCICR_PRST          0x00000002  /* PCI Reset Assert */
+  #define SH7751_PCICR_CFIN          0x00000001  /* Central Fun. Init Done */
+#define SH7751_PCILSR0             0x104         /* PCI Local Space Register0 */
+#define SH7751_PCILSR1             0x108         /* PCI Local Space Register1 */
+#define SH7751_PCILAR0             0x10C         /* PCI Local Address Register1 */
+#define SH7751_PCILAR1             0x110         /* PCI Local Address Register1 */
+#define SH7751_PCIINT              0x114         /* PCI Interrupt Register */
+  #define SH7751_PCIINT_MLCK         0x00008000  /* Master Lock Error */
+  #define SH7751_PCIINT_TABT         0x00004000  /* Target Abort Error */
+  #define SH7751_PCIINT_TRET         0x00000200  /* Target Retry Error */
+  #define SH7751_PCIINT_MFDE         0x00000100  /* Master Func. Disable Error */
+  #define SH7751_PCIINT_PRTY         0x00000080  /* Address Parity Error */
+  #define SH7751_PCIINT_SERR         0x00000040  /* SERR Detection Error */
+  #define SH7751_PCIINT_TWDP         0x00000020  /* Tgt. Write Parity Error */
+  #define SH7751_PCIINT_TRDP         0x00000010  /* Tgt. Read Parity Error Det. */
+  #define SH7751_PCIINT_MTABT        0x00000008  /* Master-Tgt. Abort Error */
+  #define SH7751_PCIINT_MMABT        0x00000004  /* Master-Master Abort Error */
+  #define SH7751_PCIINT_MWPD         0x00000002  /* Master Write PERR Detect */
+  #define SH7751_PCIINT_MRPD         0x00000002  /* Master Read PERR Detect */
+#define SH7751_PCIINTM             0x118         /* PCI Interrupt Mask Register */
+#define SH7751_PCIALR              0x11C         /* Error Address Register */
+#define SH7751_PCICLR              0x120         /* Error Command/Data Register */
+  #define SH7751_PCICLR_MPIO         0x80000000  /* Error Command/Data Register */
+  #define SH7751_PCICLR_MDMA0        0x40000000  /* DMA0 Transfer Error */
+  #define SH7751_PCICLR_MDMA1        0x20000000  /* DMA1 Transfer Error */
+  #define SH7751_PCICLR_MDMA2        0x10000000  /* DMA2 Transfer Error */
+  #define SH7751_PCICLR_MDMA3        0x08000000  /* DMA3 Transfer Error */
+  #define SH7751_PCICLR_TGT          0x04000000  /* Target Transfer Error */
+  #define SH7751_PCICLR_CMDL         0x0000000F  /* PCI Command at Error */
+#define SH7751_PCIAINT             0x130         /* Arbiter Interrupt Register */
+  #define SH7751_PCIAINT_MBKN        0x00002000  /* Master Broken Interrupt */
+  #define SH7751_PCIAINT_TBTO        0x00001000  /* Target Bus Time Out */
+  #define SH7751_PCIAINT_MBTO        0x00001000  /* Master Bus Time Out */
+  #define SH7751_PCIAINT_TABT        0x00000008  /* Target Abort */
+  #define SH7751_PCIAINT_MABT        0x00000004  /* Master Abort */
+  #define SH7751_PCIAINT_RDPE        0x00000002  /* Read Data Parity Error */
+  #define SH7751_PCIAINT_WDPE        0x00000002  /* Write Data Parity Error */
+#define SH7751_PCIAINTM            0x134         /* Arbiter Int. Mask Register */
+#define SH7751_PCIBMLR             0x138         /* Error Bus Master Register */
+  #define SH7751_PCIBMLR_REQ4        0x00000010  /* REQ4 bus master at error */
+  #define SH7751_PCIBMLR_REQ3        0x00000008  /* REQ3 bus master at error */
+  #define SH7751_PCIBMLR_REQ2        0x00000004  /* REQ2 bus master at error */
+  #define SH7751_PCIBMLR_REQ1        0x00000002  /* REQ1 bus master at error */
+  #define SH7751_PCIBMLR_REQ0        0x00000001  /* REQ0 bus master at error */
+#define SH7751_PCIDMABT            0x140         /* DMA Transfer Arb. Register */
+  #define SH7751_PCIDMABT_RRBN       0x00000001  /* DMA Arbitor Round-Robin */
+#define SH7751_PCIDPA0             0x180         /* DMA0 Transfer Addr. Register */
+#define SH7751_PCIDLA0             0x184         /* DMA0 Local Addr. Register */
+#define SH7751_PCIDTC0             0x188         /* DMA0 Transfer Cnt. Register */
+#define SH7751_PCIDCR0             0x18C         /* DMA0 Control Register */
+  #define SH7751_PCIDCR_ALGN         0x00000600  /* DMA Alignment Mode */
+  #define SH7751_PCIDCR_MAST         0x00000100  /* DMA Termination Type */
+  #define SH7751_PCIDCR_INTM         0x00000080  /* DMA Interrupt Done Mask*/
+  #define SH7751_PCIDCR_INTS         0x00000040  /* DMA Interrupt Done Status */
+  #define SH7751_PCIDCR_LHLD         0x00000020  /* Local Address Control */
+  #define SH7751_PCIDCR_PHLD         0x00000010  /* PCI Address Control*/
+  #define SH7751_PCIDCR_IOSEL        0x00000008  /* PCI Address Space Type */
+  #define SH7751_PCIDCR_DIR          0x00000004  /* DMA Transfer Direction */
+  #define SH7751_PCIDCR_STOP         0x00000002  /* Force DMA Stop */
+  #define SH7751_PCIDCR_STRT         0x00000001  /* DMA Start */
+#define SH7751_PCIDPA1             0x190         /* DMA1 Transfer Addr. Register */
+#define SH7751_PCIDLA1             0x194         /* DMA1 Local Addr. Register */
+#define SH7751_PCIDTC1             0x198         /* DMA1 Transfer Cnt. Register */
+#define SH7751_PCIDCR1             0x19C         /* DMA1 Control Register */
+#define SH7751_PCIDPA2             0x1A0         /* DMA2 Transfer Addr. Register */
+#define SH7751_PCIDLA2             0x1A4         /* DMA2 Local Addr. Register */
+#define SH7751_PCIDTC2             0x1A8         /* DMA2 Transfer Cnt. Register */
+#define SH7751_PCIDCR2             0x1AC         /* DMA2 Control Register */
+#define SH7751_PCIDPA3             0x1B0         /* DMA3 Transfer Addr. Register */
+#define SH7751_PCIDLA3             0x1B4         /* DMA3 Local Addr. Register */
+#define SH7751_PCIDTC3             0x1B8         /* DMA3 Transfer Cnt. Register */
+#define SH7751_PCIDCR3             0x1BC         /* DMA3 Control Register */
+#define SH7751_PCIPAR              0x1C0         /* PIO Address Register */
+  #define SH7751_PCIPAR_CFGEN        0x80000000  /* Configuration Enable */
+  #define SH7751_PCIPAR_BUSNO        0x00FF0000  /* Config. Bus Number */
+  #define SH7751_PCIPAR_DEVNO        0x0000FF00  /* Config. Device Number */
+  #define SH7751_PCIPAR_REGAD        0x000000FC  /* Register Address Number */
+#define SH7751_PCIMBR              0x1C4         /* Memory Base Address Register */
+  #define SH7751_PCIMBR_MASK         0xFF000000  /* Memory Space Mask */
+  #define SH7751_PCIMBR_LOCK         0x00000001  /* Lock Memory Space */
+#define SH7751_PCIIOBR             0x1C8         /* I/O Base Address Register */
+  #define SH7751_PCIIOBR_MASK         0xFFFC0000 /* IO Space Mask */
+  #define SH7751_PCIIOBR_LOCK         0x00000001 /* Lock IO Space */
+#define SH7751_PCIPINT             0x1CC         /* Power Mgmnt Int. Register */
+  #define SH7751_PCIPINT_D3           0x00000002 /* D3 Pwr Mgmt. Interrupt */
+  #define SH7751_PCIPINT_D0           0x00000001 /* D0 Pwr Mgmt. Interrupt */  
+#define SH7751_PCIPINTM            0x1D0         /* Power Mgmnt Mask Register */
+#define SH7751_PCICLKR             0x1D4         /* Clock Ctrl. Register */
+  #define SH7751_PCICLKR_PCSTP        0x00000002 /* PCI Clock Stop */
+  #define SH7751_PCICLKR_BCSTP        0x00000002 /* BCLK Clock Stop */
+/* For definitions of BCR, MCR see ... */
+#define SH7751_PCIBCR1             0x1E0         /* Memory BCR1 Register */
+#define SH7751_PCIBCR2             0x1E4         /* Memory BCR2 Register */
+#define SH7751_PCIWCR1             0x1E8         /* Wait Control 1 Register */
+#define SH7751_PCIWCR2             0x1EC         /* Wait Control 2 Register */
+#define SH7751_PCIWCR3             0x1F0         /* Wait Control 3 Register */
+#define SH7751_PCIMCR              0x1F4         /* Memory Control Register */
+#define SH7751_PCIPCTR             0x200         /* Port Control Register */
+  #define SH7751_PCIPCTR_P2EN        0x000400000 /* Port 2 Enable */
+  #define SH7751_PCIPCTR_P1EN        0x000200000 /* Port 1 Enable */
+  #define SH7751_PCIPCTR_P0EN        0x000100000 /* Port 0 Enable */
+  #define SH7751_PCIPCTR_P2UP        0x000000020 /* Port2 Pull Up Enable */
+  #define SH7751_PCIPCTR_P2IO        0x000000010 /* Port2 Output Enable */
+  #define SH7751_PCIPCTR_P1UP        0x000000008 /* Port1 Pull Up Enable */
+  #define SH7751_PCIPCTR_P1IO        0x000000004 /* Port1 Output Enable */
+  #define SH7751_PCIPCTR_P0UP        0x000000002 /* Port0 Pull Up Enable */
+  #define SH7751_PCIPCTR_P0IO        0x000000001 /* Port0 Output Enable */
+#define SH7751_PCIPDTR             0x204         /* Port Data Register */
+  #define SH7751_PCIPDTR_PB5         0x000000020 /* Port 5 Enable */
+  #define SH7751_PCIPDTR_PB4         0x000000010 /* Port 4 Enable */
+  #define SH7751_PCIPDTR_PB3         0x000000008 /* Port 3 Enable */
+  #define SH7751_PCIPDTR_PB2         0x000000004 /* Port 2 Enable */
+  #define SH7751_PCIPDTR_PB1         0x000000002 /* Port 1 Enable */
+  #define SH7751_PCIPDTR_PB0         0x000000001 /* Port 0 Enable */
+#define SH7751_PCIPDR              0x220         /* Port IO Data Register */
+
+/* Memory Control Registers */
+#define SH7751_BCR1                0xFF800000    /* Memory BCR1 Register */
+#define SH7751_BCR2                0xFF800004    /* Memory BCR2 Register */
+#define SH7751_WCR1                0xFF800008    /* Wait Control 1 Register */
+#define SH7751_WCR2                0xFF80000C    /* Wait Control 2 Register */
+#define SH7751_WCR3                0xFF800010    /* Wait Control 3 Register */
+#define SH7751_MCR                 0xFF800014    /* Memory Control Register */
+
+/* General Memory Config Addresses */
+#define SH7751_CS0_BASE_ADDR       0x0
+#define SH7751_MEM_REGION_SIZE     0x04000000
+#define SH7751_CS1_BASE_ADDR       (SH7751_CS0_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS2_BASE_ADDR       (SH7751_CS1_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS3_BASE_ADDR       (SH7751_CS2_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS4_BASE_ADDR       (SH7751_CS3_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS5_BASE_ADDR       (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS6_BASE_ADDR       (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+
+/* General PCI values */
+#define SH7751_PCI_HOST_BRIDGE         0x6
+
+/* External functions defined per platform i.e. Big Sur, SE... (these could be routed 
+ * through the machine vectors... */
+extern int pcibios_init_platform(void);
+extern int pcibios_map_platform_irq(u8 slot, u8 pin);
+
+#endif /* _PCI_SH7751_H_ */
+
index 9f5b9cb0b7ef5558d194381b1269b77b796d814a..baa613eb002d247f4352ded589f43ed5374a2992 100644 (file)
@@ -9,19 +9,33 @@
 
 #define pcibios_assign_all_busses()    1
 
+#if defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 /* These are currently the correct values for the STM overdrive board. 
  * We need some way of setting this on a board specific way, it will 
  * not be the same on other boards I think
  */
-#if 1 /* def CONFIG_SH_7750_OVERDRIVE || def CONFIG_CPU_SUBTYPE_ST40STB1 */
 #define PCIBIOS_MIN_IO         0x2000
 #define PCIBIOS_MIN_MEM                0x10000000
+
+#elif defined(CONFIG_SH_DREAMCAST)
+#define PCIBIOS_MIN_IO         0x2000
+#define PCIBIOS_MIN_MEM                0x10000000
+#elif defined(CONFIG_SH_BIGSUR) && defined(CONFIG_CPU_SUBTYPE_SH7751)
+#define PCIBIOS_MIN_IO         0x2000
+#define PCIBIOS_MIN_MEM                0xFD000000
+
+#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE) && defined(CONFIG_CPU_SUBTYPE_SH7751)
+#define PCIBIOS_MIN_IO          0x4000
+#define PCIBIOS_MIN_MEM         0xFD000000
 #endif
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
+struct pci_dev;
+
+extern void pcibios_set_master(struct pci_dev *dev);
+//static inline void pcibios_set_master(struct pci_dev *dev)
+//{
        /* No special bus mastering setup handling */
-}
+//}
 
 static inline void pcibios_penalize_isa_irq(int irq)
 {
@@ -38,8 +52,6 @@ static inline void pcibios_penalize_isa_irq(int irq)
 #include <linux/string.h>
 #include <asm/io.h>
 
-struct pci_dev;
-
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
  * NULL for PCI-like buses (ISA, EISA).
index ce7b61c75a9b9736b6b767b8fb99bfffb27fdb63..a8c7e022e5da1e5c579c35671e613bac5fde1a20 100644 (file)
@@ -17,7 +17,7 @@
  * Allocate and free page tables.
  */
 
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
        unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
        pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
@@ -28,7 +28,7 @@ static __inline__ pgd_t *get_pgd_slow(void)
        return pgd;
 }
 
-static __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
 {
        unsigned long *ret;
 
@@ -41,14 +41,14 @@ static __inline__ pgd_t *get_pgd_fast(void)
        return (pgd_t *)ret;
 }
 
-static __inline__ void free_pgd_fast(pgd_t *pgd)
+static inline void free_pgd_fast(pgd_t *pgd)
 {
        *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
        pgd_quicklist = (unsigned long *) pgd;
        pgtable_cache_size++;
 }
 
-static __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
 {
        kfree(pgd);
 }
@@ -69,33 +69,33 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long addr
 
        if ((ret = (unsigned long *)pte_quicklist) != NULL) {
                pte_quicklist = (unsigned long *)(*ret);
-               ret[0] = ret[1];
+               ret[0] = 0;
                pgtable_cache_size--;
        }
        return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
 {
        *(unsigned long *)pte = (unsigned long) pte_quicklist;
        pte_quicklist = (unsigned long *) pte;
        pgtable_cache_size++;
 }
 
-static __inline__ void pte_free_slow(pte_t *pte)
+static inline void pte_free_slow(pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-#define pte_free(pte)          pte_free_slow(pte)
-#define pgd_free(pgd)          free_pgd_slow(pgd)
+#define pte_free(pte)          pte_free_fast(pte)
+#define pgd_free(pgd)          free_pgd_fast(pgd)
 #define pgd_alloc(mm)          get_pgd_fast()
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-static __inline__ void pmd_free(pmd_t * pmd)
+static inline void pmd_free(pmd_t * pmd)
 {
 }
 
@@ -116,7 +116,7 @@ extern int do_check_pgt_cache(int, int);
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
- *
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
 extern void flush_tlb(void);
@@ -126,9 +126,9 @@ extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
                            unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
-static __inline__ void flush_tlb_pgtables(struct mm_struct *mm,
-                                         unsigned long start, unsigned long end)
-{
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+                                     unsigned long start, unsigned long end)
+{ /* Nothing to do */
 }
 
 #endif /* __ASM_SH_PGALLOC_H */
index 58199b95ec435176c46c3c06bcde933400bf7a45..8eebd4ebe2f97b03f8f5798a47d4a944e278d523 100644 (file)
@@ -17,6 +17,7 @@
 
 #define PTRS_PER_PTE   1024
 
+#ifndef __ASSEMBLY__
 #define pte_ERROR(e) \
        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
@@ -32,7 +33,7 @@
 static inline int pgd_none(pgd_t pgd)          { return 0; }
 static inline int pgd_bad(pgd_t pgd)           { return 0; }
 static inline int pgd_present(pgd_t pgd)       { return 1; }
-static inline void pgd_clear (pgd_t * pgd)     { }
+static inline void pgd_clear (pgd_t * pgdp)    { pgd_val(*(pgdp)) = 0; }
 
 /*
  * Certain architectures need to do special things when PTEs
@@ -54,5 +55,6 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
        return (pmd_t *) dir;
 }
+#endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_SH_PGTABLE_2LEVEL_H */
index a12886201dccd33abe41695f368e20ead6bc1b57..2bd0803ec669b316ac9f0408f89a841376e9fc2a 100644 (file)
@@ -3,6 +3,8 @@
 
 /* Copyright (C) 1999 Niibe Yutaka */
 
+#include <asm/pgtable-2level.h>
+
 /*
  * This file contains the functions and defines necessary to modify and use
  * the SuperH page table tree.
@@ -12,7 +14,7 @@
 #include <asm/addrspace.h>
 #include <linux/threads.h>
 
-extern pgd_t swapper_pg_dir[1024];
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern void paging_init(void);
 
 #if defined(__sh3__)
@@ -70,8 +72,6 @@ extern unsigned long empty_zero_page[1024];
 
 #endif /* !__ASSEMBLY__ */
 
-#include <asm/pgtable-2level.h>
-
 #define __beep() asm("")
 
 #define PMD_SIZE       (1UL << PMD_SHIFT)
@@ -82,13 +82,6 @@ extern unsigned long empty_zero_page[1024];
 #define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
 #define FIRST_USER_PGD_NR      0
 
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#define TWOLEVEL_PGDIR_SHIFT   22
-#define BOOT_USER_PGD_PTRS (PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
-#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
-
 #ifndef __ASSEMBLY__
 #define VMALLOC_START  P3SEG
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
@@ -123,7 +116,15 @@ extern unsigned long empty_zero_page[1024];
 
 
 /* Mask which drop software flags */
+#if defined(__sh3__)
+/*
+ * MMU on SH-3 has bug on SH-bit: We can't use it if MMUCR.IX=1.
+ * Work around: Just drop SH-bit.
+ */
+#define _PAGE_FLAGS_HARDWARE_MASK      0x1ffff1fc
+#else
 #define _PAGE_FLAGS_HARDWARE_MASK      0x1ffff1fe
+#endif
 /* Hardware flags: SZ=1 (4k-byte) */
 #define _PAGE_FLAGS_HARD               0x00000010
 
@@ -240,9 +241,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-#define __pmd_offset(address) \
-               (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-
 /* Find an entry in the third-level page table.. */
 #define __pte_offset(address) \
                ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
@@ -263,6 +261,12 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
 #define pte_to_swp_entry(pte)  ((swp_entry_t) { pte_val(pte) })
 #define swp_entry_to_pte(x)    ((pte_t) { (x).val })
 
+/*
+ * Routines for update of PTE 
+ *
+ * We just can use generic implementation, as SuperH has no SMP feature.
+ * (We needed atomic implementation for SMP)
+ */
 #include <asm-generic/pgtable.h>
 
 #endif /* !__ASSEMBLY__ */
index 145f58d50188730d91c1942276b7add6ee3d7528..83c7f1ab536b187c3244b2e088e789a5a3e7acdf 100644 (file)
@@ -23,7 +23,7 @@
 enum cpu_type {
        CPU_SH7708,             /* Represents 7707, 7708, 7708S, 7708R, 7709 */
        CPU_SH7729,             /* Represents 7709A, 7729 */
-       CPU_SH7750,
+       CPU_SH7750,     /* Represents 7750, 7751 */
        CPU_ST40STB1,
        CPU_SH_NONE
 };
@@ -38,6 +38,9 @@ struct sh_cpuinfo {
        unsigned long *pte_quick;
        unsigned long pgtable_cache_sz;
        unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+       unsigned int memory_clock;
+#endif
 };
 
 extern struct sh_cpuinfo boot_cpu_data;
@@ -76,7 +79,7 @@ extern struct sh_cpuinfo boot_cpu_data;
 
 struct sh_fpu_hard_struct {
        unsigned long fp_regs[16];
-       unsigned long long xd_regs[8];
+       unsigned long xfp_regs[16];
        unsigned long fpscr;
        unsigned long fpul;
 
@@ -86,7 +89,7 @@ struct sh_fpu_hard_struct {
 /* Dummy fpu emulator  */
 struct sh_fpu_soft_struct {
        unsigned long fp_regs[16];
-       unsigned long long xd_regs[8];
+       unsigned long xfp_regs[16];
        unsigned long fpscr;
        unsigned long fpul;
 
@@ -112,7 +115,7 @@ struct thread_struct {
 };
 
 #define INIT_MMAP \
-{ &init_mm, 0x80000000, 0xa0000000, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+{ &init_mm, 00, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
 #define INIT_THREAD  {                                         \
        sizeof(init_stack) + (long) &init_stack, /* sp */       \
index 3321bc7e8716b22055f0ed3a231d06f41a577223..71303d56ff3b2b4169cebec9d751bdf0713b73ee 100644 (file)
@@ -9,4 +9,60 @@
 extern void sh_rtc_gettimeofday(struct timeval *tv);
 extern int sh_rtc_settimeofday(const struct timeval *tv);
 
+/* RCR1 Bits */
+#define RCR1_CF                0x80    /* Carry Flag             */
+#define RCR1_CIE       0x10    /* Carry Interrupt Enable */
+#define RCR1_AIE       0x08    /* Alarm Interrupt Enable */
+#define RCR1_AF                0x01    /* Alarm Flag             */
+
+/* RCR2 Bits */
+#define RCR2_PEF       0x80    /* PEriodic interrupt Flag */
+#define RCR2_PESMASK   0x70    /* Periodic interrupt Set  */
+#define RCR2_RTCEN     0x08    /* ENable RTC              */
+#define RCR2_ADJ       0x04    /* ADJustment (30-second)  */
+#define RCR2_RESET     0x02    /* Reset bit               */
+#define RCR2_START     0x01    /* Start bit               */
+
+#if defined(__sh3__)
+/* SH-3 RTC */
+#define R64CNT         0xfffffec0
+#define RSECCNT        0xfffffec2
+#define RMINCNT        0xfffffec4
+#define RHRCNT         0xfffffec6
+#define RWKCNT         0xfffffec8
+#define RDAYCNT        0xfffffeca
+#define RMONCNT        0xfffffecc
+#define RYRCNT         0xfffffece
+#define RSECAR         0xfffffed0
+#define RMINAR         0xfffffed2
+#define RHRAR          0xfffffed4
+#define RWKAR          0xfffffed6
+#define RDAYAR         0xfffffed8
+#define RMONAR         0xfffffeda
+#define RCR1           0xfffffedc
+#define RCR2           0xfffffede
+
+#define RTC_BIT_INVERTED       0       /* No bug on SH7708, SH7709A */
+#elif defined(__SH4__)
+/* SH-4 RTC */
+#define R64CNT         0xffc80000
+#define RSECCNT        0xffc80004
+#define RMINCNT        0xffc80008
+#define RHRCNT         0xffc8000c
+#define RWKCNT         0xffc80010
+#define RDAYCNT        0xffc80014
+#define RMONCNT        0xffc80018
+#define RYRCNT         0xffc8001c  /* 16bit */
+#define RSECAR         0xffc80020
+#define RMINAR         0xffc80024
+#define RHRAR          0xffc80028
+#define RWKAR          0xffc8002c
+#define RDAYAR         0xffc80030
+#define RMONAR         0xffc80034
+#define RCR1           0xffc80038
+#define RCR2           0xffc8003c
+
+#define RTC_BIT_INVERTED       0x40    /* bug on SH7750, SH7750S */
+#endif
+
 #endif /* _ASM_RTC_H */
index d338955720635c46c5c30333e8248c859ff6da70..2c5517de6b2aa1253b9569cb41c1dd769ae7457b 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/linkage.h>
 
+#ifdef __KERNEL__
 /*
  * SMP- and interrupt-safe semaphores.
  *
@@ -84,13 +85,10 @@ asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
 asmlinkage int  __down_trylock(struct semaphore * sem);
 asmlinkage void __up(struct semaphore * sem);
-extern struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry);
-extern struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry);
-asmlinkage struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
 
 extern spinlock_t semaphore_wake_lock;
 
-extern __inline__ void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
        CHECK_MAGIC(sem->__magic);
@@ -100,7 +98,7 @@ extern __inline__ void down(struct semaphore * sem)
                __down(sem);
 }
 
-extern __inline__ int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
        int ret = 0;
 #if WAITQUEUE_DEBUG
@@ -112,7 +110,7 @@ extern __inline__ int down_interruptible(struct semaphore * sem)
        return ret;
 }
 
-extern __inline__ int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
        int ret = 0;
 #if WAITQUEUE_DEBUG
@@ -128,7 +126,7 @@ extern __inline__ int down_trylock(struct semaphore * sem)
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
  */
-extern __inline__ void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
        CHECK_MAGIC(sem->__magic);
@@ -137,4 +135,5 @@ extern __inline__ void up(struct semaphore * sem)
                __up(sem);
 }
 
+#endif
 #endif /* __ASM_SH_SEMAPHORE_H */
diff --git a/include/asm-sh/serial-bigsur.h b/include/asm-sh/serial-bigsur.h
new file mode 100644 (file)
index 0000000..4f84027
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * include/asm-sh/serial-bigsur.h
+ *
+ * Configuration details for Big Sur 16550 based serial ports 
+ * i.e. HD64465, PCMCIA, etc.
+ */
+
+#ifndef _ASM_SERIAL_BIGSUR_H
+#define _ASM_SERIAL_BIGSUR_H
+#include <asm/hd64465.h>
+
+#define BASE_BAUD (3379200 / 16)
+
+/* Leave 2 spare for possible PCMCIA serial cards */
+#define RS_TABLE_SIZE  3
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+
+#define STD_SERIAL_PORT_DEFNS                   \
+        /* UART CLK   PORT IRQ     FLAGS        */                      \
+        { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */ 
+
+
+#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
+
+/* XXX: This should be moved ino irq.h */
+#define irq_cannonicalize(x) (x)
+
+#endif /* _ASM_SERIAL_BIGSUR_H */
index 580019ae41f4e6f2a192a753988d836c996ba17e..2d5a040c6f6878b106ebb836c2eb63a516cc824d 100644 (file)
@@ -12,8 +12,9 @@
 
 #ifdef CONFIG_SH_EC3104
 #include <asm/serial-ec3104.h>
+#elif defined (CONFIG_SH_BIGSUR)
+#include <asm/serial-bigsur.h>
 #else
-
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
  *
index 5e539b0ae68a47a62ffc38a4d10af8d82c111666..998a8abfb2a748421d7ee725ad28b1fd637ceae8 100644 (file)
@@ -4,11 +4,29 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define cpu_bh_disable(cpu)    do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count(cpu)--; } while (0)
+#define local_bh_disable()                     \
+do {                                           \
+       local_bh_count(smp_processor_id())++;   \
+       barrier();                              \
+} while (0)
 
-#define local_bh_disable()     cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()      cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable()                    \
+do {                                           \
+       barrier();                              \
+       local_bh_count(smp_processor_id())--;   \
+} while (0)
+
+#define local_bh_enable()                              \
+do {                                                   \
+       if (!--local_bh_count(smp_processor_id())       \
+           && softirq_pending(smp_processor_id())) {   \
+               do_softirq();                           \
+               __sti();                                \
+       }                                               \
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) set_bit((nr), &softirq_pending(cpu));
+#define raise_softirq(nr)      __cpu_raise_softirq(smp_processor_id(), (nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
index d85e4e4066d4493075bc79f410e63a49f7d0fdfd..77509215ebecc2d106e3969c7165cc724256bb0b 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #define __HAVE_ARCH_STRCPY
-extern __inline__ char *strcpy(char *__dest, const char *__src)
+static __inline__ char *strcpy(char *__dest, const char *__src)
 {
        register char *__xdest = __dest;
        unsigned long __dummy;
@@ -26,7 +26,7 @@ extern __inline__ char *strcpy(char *__dest, const char *__src)
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+static __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
 {
        register char *__xdest = __dest;
        unsigned long __dummy;
@@ -52,7 +52,7 @@ extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
 }
 
 #define __HAVE_ARCH_STRCMP
-extern __inline__ int strcmp(const char *__cs, const char *__ct)
+static __inline__ int strcmp(const char *__cs, const char *__ct)
 {
        register int __res;
        unsigned long __dummy;
@@ -78,7 +78,7 @@ extern __inline__ int strcmp(const char *__cs, const char *__ct)
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+static __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
 {
        register int __res;
        unsigned long __dummy;
index 6888368aab99f12c70220d44074348bc0ea19231..78b798e975d0339dc6813c4ed0aea487d4858525 100644 (file)
@@ -31,7 +31,7 @@
 
 struct user_fpu_struct {
        unsigned long fp_regs[16];
-       unsigned long long xd_regs[8];
+       unsigned long xfp_regs[16];
        unsigned long fpscr;
        unsigned long fpul;
 };
index 1b6b951e8b5971bdb008c1b4805ccb9e99c0362b..be785d31c96f0ad3e6cfe410e788a98b95a7e36d 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __LINUX_MII_H__
 #define __LINUX_MII_H__
 
+#include <linux/types.h>
+
 /* Inside the Happy Meal transceiver is the physical layer, they use an
  * implementations for National Semiconductor, part number DP83840VCE.
  * You can retrieve the data sheets and programming docs for this beast
 #define CSCONFIG_RESV4          0x4000  /* Unused...                   */
 #define CSCONFIG_NDISABLE       0x8000  /* Disable NRZI                */
 
+
+/* This structure is used in all SIOCxMIIxxx ioctl calls */
+struct mii_ioctl_data {
+       u16             phy_id;
+       u16             reg_num;
+       u16             val_in;
+       u16             val_out;
+};
+
+
 /**
  * mii_nway_result
  * @negotiated: value of MII ANAR and'd with ANLPAR
index 33ffddc50d156304efe61704b89db6a9d7950b85..d360c7533d9f551c7bc80cfe71b7cca912ec3ec3 100644 (file)
 
 #define SIOCETHTOOL    0x8946          /* Ethtool interface            */
 
+#define SIOCGMIIPHY    0x8947          /* Get address of MII PHY in use. */
+#define SIOCGMIIREG    0x8948          /* Read MII PHY register.       */
+#define SIOCSMIIREG    0x8949          /* Write MII PHY register.      */
+
 /* ARP cache control calls. */
                    /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
 #define SIOCDARP       0x8953          /* delete ARP table entry       */
index 054bd984534fb118b5aae45685d00bf48842b63d..232f5a09a499ada89c87fe27598aceb5f2d95a70 100644 (file)
@@ -38,7 +38,9 @@
 #define VMODE_1152_870_75      18      /* 1152x870, 75Hz */
 #define VMODE_1280_960_75      19      /* 1280x960, 75Hz */
 #define VMODE_1280_1024_75     20      /* 1280x1024, 75Hz */
-#define VMODE_MAX              20
+#define VMODE_1152_768_60      21      /* 1152x768, 60Hz     Titanium PowerBook */
+#define VMODE_1600_1024_60     22      /* 1600x1024, 60Hz 22" Cinema Display */
+#define VMODE_MAX              22
 #define VMODE_CHOOSE           99
 
 #define CMODE_NVRAM            -1
index ff097124bda329f86f4f29fd80121bb4ee1a7e25..9143185b5e2d55a3565313d92dcababc15da1fef 100644 (file)
@@ -1104,7 +1104,7 @@ static void show_task(struct task_struct * p)
        int state;
        static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
 
-       printk("%-8s  ", p->comm);
+       printk("%-13.13s ", p->comm);
        state = p->state ? ffz(~p->state) + 1 : 0;
        if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
                printk(stat_nam[state]);
@@ -1132,21 +1132,21 @@ static void show_task(struct task_struct * p)
                printk("%5d ", p->p_cptr->pid);
        else
                printk("      ");
-       if (!p->mm)
-               printk(" (L-TLB) ");
-       else
-               printk(" (NOTLB) ");
        if (p->p_ysptr)
                printk("%7d", p->p_ysptr->pid);
        else
                printk("       ");
        if (p->p_osptr)
-               printk(" %5d\n", p->p_osptr->pid);
+               printk(" %5d", p->p_osptr->pid);
+       else
+               printk("      ");
+       if (!p->mm)
+               printk(" (L-TLB)\n");
        else
-               printk("\n");
+               printk(" (NOTLB)\n");
 
-#if defined(CONFIG_X86) || defined(CONFIG_SPARC64)
-/* This is very useful, but only works on x86 and sparc64 right now */
+#if defined(CONFIG_X86) || defined(CONFIG_SPARC64) || defined(CONFIG_ARM)
+/* This is very useful, but only works on ARM, x86 and sparc64 right now */
        {
                extern void show_trace_task(struct task_struct *tsk);
                show_trace_task(p);
index 5cfa1141877edd2e0914a49d0e4267995f49eb92..7163bdace41953beeb764c4338872388a2cb29d6 100644 (file)
@@ -448,7 +448,6 @@ try_again:
                 * to give up than to deadlock the kernel looping here.
                 */
                if (gfp_mask & __GFP_WAIT) {
-                       memory_pressure++;
                        if (!order || free_shortage()) {
                                int progress = try_to_free_pages(gfp_mask);
                                if (progress || (gfp_mask & __GFP_IO))
index c85c452ecf7765d31c855c23b151551ab669f834..8275cab9445efbddbaa2fb1acf7f84d59357c197 100644 (file)
@@ -391,6 +391,7 @@ struct page * reclaim_page(zone_t * zone)
        goto out;
 
 found_page:
+       memory_pressure++;
        del_page_from_inactive_clean_list(page);
        UnlockPage(page);
        page->age = PAGE_AGE_START;
@@ -400,7 +401,6 @@ found_page:
 out:
        spin_unlock(&pagemap_lru_lock);
        spin_unlock(&pagecache_lock);
-       memory_pressure++;
        return page;
 }
 
index 8435f53754f9acaec07a55eb24bc0e92d7852cfd..c467acbe633dcf093ac9f5c7189e14bdb4709814 100644 (file)
@@ -685,8 +685,6 @@ static struct notifier_block clip_inet_notifier = {
 
 static void atmarpd_close(struct atm_vcc *vcc)
 {
-       struct sk_buff *skb;
-
        DPRINTK("atmarpd_close\n");
        atmarpd = NULL; /* assumed to be atomic */
        barrier();
@@ -695,7 +693,7 @@ static void atmarpd_close(struct atm_vcc *vcc)
        if (skb_peek(&vcc->recvq))
                printk(KERN_ERR "atmarpd_close: closing with requests "
                    "pending\n");
-       while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
+       skb_queue_purge(&vcc->recvq);
        DPRINTK("(done)\n");
 }
 
index 5eb030da5368f0b66ebb3e1266ed351a53a41e62..37386ca2690f967d5c5421e4365a6eaea95c7e7b 100644 (file)
@@ -544,7 +544,7 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
 {
        struct atm_dev *dev;
        struct atm_vcc *vcc;
-       int *tmp_buf;
+       int *tmp_buf, *tmp_p;
        void *buf;
        int error,len,size,number, ret_val;
 
@@ -598,14 +598,13 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
                                ret_val = -ENOMEM;
                                goto done;
                        }
+                       tmp_p = tmp_buf;
                        for (dev = atm_devs; dev; dev = dev->next)
-                               *tmp_buf++ = dev->number;
-                       if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
-                               ret_val = -EFAULT;
-                               goto done;
-                       }
-                       ret_val = put_user(size,
-                           &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+                               *tmp_p++ = dev->number;
+                       ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
+                           put_user(size, &((struct atm_iobuf *) arg)->length)
+                           ) ? -EFAULT : 0;
+                       kfree(tmp_buf);
                        goto done;
                case SIOCGSTAMP: /* borrowed from IP */
                        if (!vcc->timestamp.tv_sec) {
index 2e0f697bb5d763cb5d06f613b8a70165b51ae51e..275a8bc261e6236656b02a1fe001f1c399a34a6a 100644 (file)
@@ -281,6 +281,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
                                dev->name,
                                skb->len,skb->truesize);
                         nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
+                        if (nb == NULL) {
+                                dev_kfree_skb(skb);
+                                return 0;
+                        }
                         memcpy(nb,skb->data,skb->len);
                         kfree(skb->head);
                         skb->head = skb->data = nb;
@@ -1796,6 +1800,10 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
         entry = lec_arp_find(priv, mac_addr);
         if (!entry) {
                 entry = make_entry(priv, mac_addr);
+                if (!entry) {
+                        lec_arp_unlock(priv);
+                        return;
+                }
                 entry->status = ESI_UNKNOWN;
                 lec_arp_put(priv->lec_arp_tables, entry);
                 /* Temporary, changes before end of function */
@@ -1890,6 +1898,10 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
                         ioc_data->atm_addr[16],ioc_data->atm_addr[17],
                         ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
                 entry = make_entry(priv, bus_mac);
+                if (entry == NULL) {
+                        lec_arp_unlock(priv);
+                        return;
+                }
                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
                 memset(entry->mac_addr, 0, ETH_ALEN);
                 entry->recv_vcc = vcc;
@@ -1967,6 +1979,10 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
         /* Not found, snatch address from first data packet that arrives from
            this vcc */
         entry = make_entry(priv, bus_mac);
+        if (!entry) {
+                lec_arp_unlock(priv);
+                return;
+        }
         entry->vcc = vcc;
         entry->old_push = old_push;
         memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
index cb6179483cb42ca38d9eac6609abcfc311de051a..69bec4cf34ef330603c3f9558371ca11b596df3a 100644 (file)
@@ -772,6 +772,8 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
        if (mpc == NULL) {
                dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
                mpc = alloc_mpc();
+               if (mpc == NULL)
+                       return -ENOMEM;
                mpc->dev_num = arg;
                mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
        }
index fab17e7c66e34348b50f97d6b233539564eef39e..278317ca8a8571ef65b2834e2ab343c3e42d0b63 100644 (file)
@@ -211,14 +211,13 @@ static void purge_vccs(struct atm_vcc *vcc)
 
 static void sigd_close(struct atm_vcc *vcc)
 {
-       struct sk_buff *skb;
        struct atm_dev *dev;
 
        DPRINTK("sigd_close\n");
        sigd = NULL;
        if (skb_peek(&vcc->recvq))
                printk(KERN_ERR "sigd_close: closing with requests pending\n");
-       while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
+       skb_queue_purge(&vcc->recvq);
        purge_vccs(nodev_vccs);
 
        spin_lock (&atm_dev_lock);
index 2f9929a488fe6c8413c4efb365c1397c66c14ae7..c55b21f51b136e09844a2455c518c0d6fee5cd50 100644 (file)
@@ -1488,7 +1488,11 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char *opt
                default:
 #ifdef CONFIG_NETFILTER
                {
-                       int val, len = *optlen;
+                       int val, len;
+                       
+                       if(get_user(len, optlen))
+                               return -EFAULT;
+                       
                        val = nf_getsockopt(sk, PF_DECnet, optname, 
                                                        optval, &len);
                        if (val >= 0)
index 68606eb5fff0adc1fa3a83086fe64ca32ec2c3b5..0ad59327f32b6a7b52552ab4a06fa6e730b53a67 100644 (file)
@@ -9,6 +9,9 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  * 
+ * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith
+ *                               added netlink_proto_exit
+ *
  */
 
 #include <linux/config.h>
@@ -985,4 +988,11 @@ static int __init netlink_proto_init(void)
        return 0;
 }
 
+static void __exit netlink_proto_exit(void)
+{
+       sock_unregister(PF_NETLINK);
+       remove_proc_entry("net/netlink", NULL);
+}
+
 module_init(netlink_proto_init);
+module_exit(netlink_proto_exit);
index 8289a1fe48719ec6972cdc3298db073ecfaf5455..d6d5cbd641b53692eda56aace453beef8b88b127 100644 (file)
@@ -89,6 +89,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
        struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
        struct sk_buff *skbn;
        unsigned char *bp = skb->data;
+       int len;
 
        if (arp_find(bp + 7, skb)) {
                return 1;
@@ -113,13 +114,15 @@ static int nr_rebuild_header(struct sk_buff *skb)
 
        kfree_skb(skb);
 
+       len = skbn->len;
+       
        if (!nr_route_frame(skbn, NULL)) {
                kfree_skb(skbn);
                stats->tx_errors++;
        }
 
        stats->tx_packets++;
-       stats->tx_bytes += skbn->len;
+       stats->tx_bytes += len;
 
        return 1;
 }
index 5290ae024957d35db37d0e6a0a8cf85a5d0b9708..c943c09646bbe12c10f4d2a0cab697bb6079bc40 100644 (file)
@@ -92,10 +92,6 @@ static void nr_loopback_timer(unsigned long param)
 
 void __exit nr_loopback_clear(void)
 {
-       struct sk_buff *skb;
-
        del_timer(&loopback_timer);
-
-       while ((skb = skb_dequeue(&loopback_queue)) != NULL)
-               kfree_skb(skb);
+       skb_queue_purge(&loopback_queue);
 }
index fee0478fa1705f4092273793ffb49c1c2823fac1..bd30fa7adfe857d4283793d6fbf08cf3f254d513 100644 (file)
  */
 void nr_clear_queues(struct sock *sk)
 {
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
-               kfree_skb(skb);
-
-       while ((skb = skb_dequeue(&sk->protinfo.nr->ack_queue)) != NULL)
-               kfree_skb(skb);
-
-       while ((skb = skb_dequeue(&sk->protinfo.nr->reseq_queue)) != NULL)
-               kfree_skb(skb);
-
-       while ((skb = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL)
-               kfree_skb(skb);
+       skb_queue_purge(&sk->write_queue);
+       skb_queue_purge(&sk->protinfo.nr->ack_queue);
+       skb_queue_purge(&sk->protinfo.nr->reseq_queue);
+       skb_queue_purge(&sk->protinfo.nr->frag_queue);
 }
 
 /*
index f0b7cc65c6479703636a81a1a2c4f16625a59777..8c45fbe65085ada1df4d3c9f6a06feee3067f35e 100644 (file)
@@ -121,6 +121,7 @@ static int rose_rebuild_header(struct sk_buff *skb)
        if (!rose_route_frame(skbn, NULL)) {
                kfree_skb(skbn);
                stats->tx_errors++;
+               return 1;
        }
 
        stats->tx_packets++;
index 604937be19fc83f71b5914fe309974b2072733dd..f21ecf5c464936fa13f5d4e63664f0fa77626929 100644 (file)
@@ -611,10 +611,10 @@ static int device_setup (wan_device_t *wandev, wandev_conf_t *u_conf)
 
        if (conf->data_size && conf->data){
                if(conf->data_size > 128000 || conf->data_size < 0) {
-                       kfree(conf);
                        printk(KERN_INFO 
                            "%s: ERROR, Invalid firmware data size %i !\n",
                                        wandev->name, conf->data_size);
+                       kfree(conf);
                        return -EINVAL;;
                }
 
@@ -764,23 +764,23 @@ static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf)
 {
        wanif_conf_t conf;
        netdevice_t *dev=NULL;
-      #ifdef CONFIG_WANPIPE_MULTPPP
+#ifdef CONFIG_WANPIPE_MULTPPP
        struct ppp_device *pppdev=NULL;
-      #endif
+#endif
        int err;
 
        if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
                return -ENODEV;
        
-      #if defined (LINUX_2_1) || defined (LINUX_2_4)   
+#if defined (LINUX_2_1) || defined (LINUX_2_4) 
        if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
                return -EFAULT;
-      #else
+#else
         err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t));
         if (err)
                 return err;
         memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t));
-      #endif
+#endif
                
        if (conf.magic != ROUTER_MAGIC)
                return -EINVAL;
@@ -797,13 +797,14 @@ static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf)
                }
                memset(pppdev, 0, sizeof(struct ppp_device));
 
-             #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
                pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
                if (pppdev->dev == NULL){
+                       kfree(pppdev);
                        return -ENOBUFS;
                }
                memset(pppdev->dev, 0, sizeof(netdevice_t));
-             #endif
+#endif
                
                err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf);
                
index 82f1efc2d1c8077c2b938c72b0987a73b15551cb..a97afb450d85392ede0cbd50e54f1edcf9e08e12 100644 (file)
@@ -813,8 +813,10 @@ typedef struct wan_stat_entry
                offs = file->f_pos;
                if (offs < pos) {
                        len = min(pos - offs, count);
-                       if(copy_to_user(buf, (page + offs), len))
+                       if (copy_to_user(buf, (page + offs), len)) {
+                               kfree(page);
                                return -EFAULT;
+                       }
                        file->f_pos += len;
                }
                else