]> git.hungrycats.org Git - linux/commitdiff
v2.4.9.11 -> v2.4.9.12
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:18:59 +0000 (20:18 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:18:59 +0000 (20:18 -0800)
  - Alan Cox: much more merging
  - Pete Zaitcev: ymfpci race fixes
  - Andrea Arkangeli: VM race fix and OOM tweak.
  - Arjan Van de Ven: merge RH kernel fixes
  - Andi Kleen: use more readable 'likely()/unlikely()' instead of __builtin_expect()
  - Keith Owens: fix 64-bit ELF types
  - Gerd Knorr: mark more broken PCI bridges, update btaudio driver
  - Paul Mackerras: powermac driver update
  - me: clean up PTRACE_DETACH to use common infrastructure

142 files changed:
Documentation/Changes
Documentation/nmi_watchdog.txt
Documentation/sound/btaudio
Documentation/sysrq.txt
Makefile
arch/alpha/kernel/ptrace.c
arch/arm/kernel/ptrace.c
arch/cris/kernel/ptrace.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/Makefile
arch/i386/kernel/apic.c
arch/i386/kernel/apm.c
arch/i386/kernel/dmi_scan.c
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/i8259.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/mpparse.c
arch/i386/kernel/nmi.c [new file with mode: 0644]
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/time.c
arch/i386/kernel/traps.c
arch/i386/lib/usercopy.c
arch/i386/mm/fault.c
arch/ia64/kernel/ptrace.c
arch/m68k/kernel/ptrace.c
arch/mips/kernel/ptrace.c
arch/mips64/kernel/ptrace.c
arch/parisc/kernel/ptrace.c
arch/ppc/kernel/ptrace.c
arch/s390/kernel/ptrace.c
arch/s390x/kernel/ptrace.c
arch/sh/kernel/ptrace.c
arch/sparc/kernel/ptrace.c
arch/sparc64/kernel/ptrace.c
drivers/atm/iphase.c
drivers/block/cciss.c
drivers/block/cpqarray.c
drivers/block/paride/bpck6.c
drivers/block/rd.c
drivers/char/agp/agp.h
drivers/char/agp/agpgart_be.c
drivers/char/console.c
drivers/char/keyboard.c
drivers/char/pc_keyb.c
drivers/char/random.c
drivers/char/sonypi.c
drivers/char/sonypi.h
drivers/char/sysrq.c
drivers/char/tty_ioctl.c
drivers/char/vt.c
drivers/ide/Config.in
drivers/ide/Makefile
drivers/ide/ataraid.c [new file with mode: 0644]
drivers/ide/ataraid.h [new file with mode: 0644]
drivers/ide/hptraid.c [new file with mode: 0644]
drivers/ide/hptraid.h [new file with mode: 0644]
drivers/ide/pdcraid.c [new file with mode: 0644]
drivers/ide/pdcraid.h [new file with mode: 0644]
drivers/ieee1394/nodemgr.c
drivers/input/keybdev.c
drivers/macintosh/adb.c
drivers/macintosh/adbhid.c
drivers/macintosh/mac_keyb.c
drivers/mtd/maps/Config.in
drivers/mtd/nand/Config.in
drivers/net/Config.in
drivers/net/Makefile
drivers/net/aironet4500_card.c
drivers/net/aironet4500_core.c
drivers/net/aironet4500_proc.c
drivers/net/bmac.c
drivers/net/gmac.c
drivers/net/gmac.h
drivers/net/irda/irda-usb.c
drivers/net/ns83820.c
drivers/net/pcmcia/Config.in
drivers/net/pcmcia/Makefile
drivers/net/pcmcia/xircom_cb.c [new file with mode: 0644]
drivers/net/wireless/airo.c
drivers/net/wireless/hermes.c
drivers/net/wireless/hermes.h
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco.h
drivers/net/wireless/orinoco_cs.c
drivers/pci/pci.c
drivers/pci/quirks.c
drivers/pcmcia/i82365.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/aic7xxx_old/aic7xxx_proc.c
drivers/scsi/mesh.c
drivers/sound/btaudio.c
drivers/sound/sb_card.c
drivers/sound/ymfpci.c
drivers/usb/CDCEther.c
drivers/usb/scanner.c
drivers/usb/scanner.h
drivers/usb/storage/scsiglue.c
drivers/usb/usb-uhci.c
drivers/usb/wacom.c
drivers/video/sun3fb.c
fs/buffer.c
fs/exec.c
fs/namei.c
include/asm-i386/apic.h
include/asm-i386/io_apic.h
include/asm-i386/irq.h
include/asm-i386/mpspec.h
include/asm-i386/page.h
include/linux/compiler.h [new file with mode: 0644]
include/linux/elf.h
include/linux/irq.h
include/linux/list.h
include/linux/major.h
include/linux/mm.h
include/linux/nmi.h [new file with mode: 0644]
include/linux/pci.h
include/linux/prefetch.h
include/linux/sched.h
include/linux/sysctl.h
include/linux/sysrq.h
kernel/fork.c
kernel/ptrace.c
kernel/sched.c
kernel/sys.c
kernel/sysctl.c
mm/bootmem.c
mm/highmem.c
mm/memory.c
mm/page_alloc.c
mm/page_io.c
mm/slab.c
mm/swap.c
mm/vmscan.c
net/netsyms.c
scripts/mkspec [new file with mode: 0644]
scripts/mkversion [new file with mode: 0644]

index 65bc2ac4dcf2732047ec2919265f9d087c085633..6dc50f50bf04c8f5922f4e9bedeac89271c73da4 100644 (file)
@@ -48,7 +48,7 @@ necessary on all systems; obviously, if you don't have any PCMCIA (PC
 Card) hardware, for example, you probably needn't concern yourself
 with pcmcia-cs.
 
-o  Gnu C                  2.91.66                 # gcc --version
+o  Gnu C                  2.95.3                  # gcc --version
 o  Gnu make               3.77                    # make --version
 o  binutils               2.9.1.0.25              # ld -v
 o  util-linux             2.10o                   # fdformat --version
@@ -70,17 +70,23 @@ computer. The next paragraph applies to users of x86 CPUs, but not
 necessarily to users of other CPUs. Users of other CPUs should obtain
 information about their gcc version requirements from another source.
 
-The recommended compiler for the kernel is egcs 1.1.2 (gcc 2.91.66), and it
-should be used when you need absolute stability. You may use gcc 2.95.x
-instead if you wish, although it may cause problems. Later versions of gcc
-have not received much testing for Linux kernel compilation, and there are
+The recommended compiler for the kernel is gcc 2.95.3 or .4, and it
+should be used when you need absolute stability. You may use gcc 3.0.x
+instead if you wish, although it may cause problems. Later  versions of gcc 
+have not received much testing for Linux kernel compilation, and there are 
 almost certainly bugs (mainly, but not exclusively, in the kernel) that
 will need to be fixed in order to use these compilers. In any case, using
 pgcc instead of egcs or plain gcc is just asking for trouble.
 
 Note that gcc 2.7.2.3 is no longer a supported kernel compiler. The kernel
 no longer works around bugs in gcc 2.7.2.3 and, in fact, will refuse to
-be compiled with it.
+be compiled with it. egcs-1.1.2 has register allocation problems in very
+obscure cases. We have ensured the kernel does not trip these in any known
+situation. The 2.5 tree is likely to drop egcs-1.1.2 workarounds.
+
+The Red Hat gcc 2.96 compiler subtree can also be used to build this tree.
+You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build
+the kernel correctly.
 
 In addition, please pay attention to compiler optimization.  Anything
 greater than -O2 may not be wise.  Similarly, if you choose to use gcc-2.95.x
index 2eb5a8bbc5e063fe827ac50911ea46b79f15d9a9..93b42171b96a60c94110df6569f3f26bb8cc41c3 100644 (file)
@@ -1,19 +1,27 @@
 
-Is your SMP system locking up unpredictably? No keyboard activity, just
+Is your ix86 system locking up unpredictably? No keyboard activity, just
 a frustrating complete hard lockup? Do you want to help us debugging
 such lockups? If all yes then this document is definitely for you.
 
-on Intel SMP hardware there is a feature that enables us to generate
-'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get
-executed even if the system is otherwise locked up hard) This can be
-used to debug hard kernel lockups. By executing periodic NMI interrupts,
-the kernel can monitor whether any CPU has locked up, and print out
-debugging messages if so.  You can enable/disable the NMI watchdog at boot
-time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant
-lilo.conf entry:
+On Intel and similar ix86 type hardware there is a feature that enables
+us to generate 'watchdog NMI interrupts'.  (NMI: Non Maskable Interrupt
+which get executed even if the system is otherwise locked up hard).
+This can be used to debug hard kernel lockups.  By executing periodic
+NMI interrupts, the kernel can monitor whether any CPU has locked up,
+and print out debugging messages if so.  You must enable the NMI
+watchdog at boot time with the 'nmi_watchdog=n' boot parameter.  Eg.
+the relevant lilo.conf entry:
 
         append="nmi_watchdog=1"
 
+For SMP machines and UP machines with an IO-APIC use nmi_watchdog=1.
+For UP machines without an IO-APIC use nmi_watchdog=2, this only works
+for some processor types.  If in doubt, boot with nmi_watchdog=1 and
+check the NMI count in /proc/interrupts; if the count is zero then
+reboot with nmi_watchdog=2 and check the NMI count.  If it is still
+zero then log a problem, you probably have a processor that needs to be
+added to the nmi code.
+
 A 'lockup' is the following scenario: if any CPU in the system does not
 execute the period local timer interrupt for more than 5 seconds, then
 the NMI handler generates an oops and kills the process. This
@@ -24,8 +32,9 @@ then the system has crashed so hard (eg. hardware-wise) that either it
 cannot even accept NMI interrupts, or the crash has made the kernel
 unable to print messages.
 
-NOTE: currently the NMI-oopser is enabled unconditionally on x86 SMP
-boxes.
+NOTE: starting with 2.4.2-ac18 the NMI-oopser is disabled by default,
+you have to enable it with a boot time parameter.  Prior to 2.4.2-ac18
+the NMI-oopser is enabled unconditionally on x86 SMP boxes.
 
 [ feel free to send bug reports, suggestions and patches to
   Ingo Molnar <mingo@redhat.com> or the Linux SMP mailing
index 97f0401eb8cfe7ace54abe4f3409f8300b8563d5..1a693e69d44b203d8bede7ccb5f99db435963493 100644 (file)
@@ -31,23 +31,28 @@ Still somewhat experimental.  The driver should work stable, i.e. it
 should'nt crash your box.  It might not work as expected, have bugs,
 not being fully OSS API compilant, ...
 
+Latest versions are available from http://bytesex.org/bttv/, the
+driver is in the bttv tarball.  Kernel patches might be available too,
+have a look at http://bytesex.org/bttv/listing.html.
+
+The chip knows two different modes.  btaudio registers two dsp
+devices, one for each mode.  They can not be used at the same time.
+
 
 Digital audio mode
 ==================
 
-The chip knows different modes.  Right now you have to pick the one you
-want to use at insmod time.  Digital audio mode is the default.  The
-chip gives you 16 bit stereo sound with ~32 kHz sample rate.  According
-to the specs it should be possible to get up to 48 kHz, but I havn't
-figured out yet how this works.  The specs are not very verbose :-(
+The chip gives you 16 bit stereo sound.  The sample rate depends on
+the external source which feeds the bt878 with digital sound via I2S
+interface.  There is a insmod option (rate) to tell the driver which
+sample rate the hardware uses (32000 is the default).
 
-Lower sample rates are possible too, but the code isn't written yet.
-For now you are limited to the fixed 32 kHz.  Mono works throuth, the
-driver will do that in software for you.
+One possible source for digital sound is the msp34xx audio processor
+chip which provides digital sound via I2S with 32 kHz sample rate.  My
+Hauppauge board works this way.
 
-With my Hauppauge I get clear sound, but I got also reports saying that
-digital audio mode does'nt work.  Guess Hauppauge connected the msp34xx
-output to the bt878's I2S digital audio input port.
+The Osprey-200 reportly gives you digital sound with 44100 Hz sample
+rate.  It is also possible that you get no sound at all.
 
 
 analog mode (A/D)
@@ -67,11 +72,17 @@ With my Hauppauge I get noisy sound on the second input (mapped to line2
 by the mixer device).  Others get a useable signal on line1.
 
 
-more hints
-==========
+some examples
+=============
+
+* read audio data from btaudio (dsp2), send to es1730 (dsp,dsp1):
+  $ sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp
+
+* read audio data from btaudio, send to esound daemon (which might be
+  running on another host):
+  $ sox -c 2 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -r 32000
+  $ sox -c 1 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -m -r 32000
 
-/me uses "sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp"
-to dump audio data from btaudio (dsp2) to es1730 (dsp,dsp1).
 
 Have fun,
 
index 5c53ac206f70a6623b0e02cd62aa0ba83a6d6663..d0238eef2bf3e6902def0ed39e1ffd0a49b57457 100644 (file)
@@ -1,26 +1,27 @@
+Linux Magic System Request Key Hacks
+Documentation for sysrq.c version 1.15
+Last update: $Date: 2001/01/28 10:15:59 $
 
-                      MAGIC SYSRQ KEY DOCUMENTATION v1.32
-                     ------------------------------------
-                        [Sat Apr  8 22:15:03 CEST 2000]
-
-*  What is the magic SysRQ key?
+*  What is the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-It is a 'magical' key combo you can hit which kernel will respond to
+It is a 'magical' key combo you can hit which the kernel will respond to
 regardless of whatever else it is doing, unless it is completely locked up.
 
-*  How do I enable the magic SysRQ key?
+*  How do I enable the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when
-configuring the kernel. This option is only available in 2.1.x or later
-kernels. Once you boot the new kernel, you need to enable it manually 
-using following command:
+configuring the kernel. When running on a kernel with SysRq compiled in, it
+may be DISABLED at run-time using following command:
+
+        echo "0" > /proc/sys/kernel/sysrq
 
-        echo "1" > /proc/sys/kernel/sysrq
+Note that previous versions disabled sysrq by default, and you were required
+to specifically enable it at run-time. That is not the case any longer.
 
-*  How do I use the magic SysRQ key?
+*  How do I use the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-On x86   - You press the key combo 'ALT-SysRQ-<command key>'. Note - Some
-           (older?) may not have a key labeled 'SysRQ'. The 'SysRQ' key is
+On x86   - You press the key combo 'ALT-SysRq-<command key>'. Note - Some
+           keyboards may not have a key labeled 'SysRq'. The 'SysRq' key is
            also known as the 'Print Screen' key.
 
 On SPARC - You press 'ALT-STOP-<command key>', I believe.
@@ -33,14 +34,14 @@ On PowerPC - Press 'ALT - Print Screen (or F13) - <command key>,
              Print Screen (or F13) - <command key> may suffice.
 
 On other - If you know of the key combos for other architectures, please
-           let me know so I can add them to this section. 
+           let me know so I can add them to this section.
 
 *  What are the 'command' keys?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 'r'     - Turns off keyboard raw mode and sets it to XLATE.
 
-'k'     - Secure Access Key (SAK) Kills all programs on the current virtual 
-         console. NOTE: See important comments below in SAK section.
+'k'     - Secure Access Key (SAK) Kills all programs on the current virtual
+          console. NOTE: See important comments below in SAK section.
 
 'b'     - Will immediately reboot the system without syncing or unmounting
           your disks.
@@ -70,8 +71,8 @@ On other - If you know of the key combos for other architectures, please
 'l'     - Send a SIGKILL to all processes, INCLUDING init. (Your system
           will be non-functional after this.)
 
-'h'    - Will display help ( actually any other key than those listed
-         above will display help. but 'h' is easy to remember :-)
+'h'     - Will display help ( actually any other key than those listed
+          above will display help. but 'h' is easy to remember :-)
 
 *  Okay, so what can I use them for?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -83,8 +84,8 @@ when you would try to login. It will kill all programs on given console
 and thus letting you make sure that the login prompt you see is actually
 the one from init, not some trojan program.
 IMPORTANT:In its true form it is not a true SAK like the one in   :IMPORTANT
-IMPORTATN:c2 compliant systems, and it should be mistook as such. :IMPORTANT
-       It seems other find it useful as (System Attention Key) which is
+IMPORTANT:c2 compliant systems, and it should be mistook as such. :IMPORTANT
+       It seems other find it useful as (System Attention Key) which is
 useful when you want to exit a program that will not let you switch consoles.
 (For example, X or a svgalib program.)
 
@@ -93,7 +94,7 @@ and 'U'mount first.
 
 'S'ync is great when your system is locked up, it allows you to sync your
 disks and will certainly lessen the chance of data loss and fscking. Note
-that the sync hasn't taken place until you see the "OK" and "Done" appear 
+that the sync hasn't taken place until you see the "OK" and "Done" appear
 on the screen. (If the kernel is really in strife, you may not ever get the
 OK or Done message...)
 
@@ -111,30 +112,72 @@ t'E'rm and k'I'll are useful if you have some sort of runaway process you
 are unable to kill any other way, especially if it's spawning other
 processes.
 
-*  Sometimes SysRQ seems to get 'stuck' after using it, what can I do?
+*  Sometimes SysRq seems to get 'stuck' after using it, what can I do?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 That happens to me, also. I've found that tapping shift, alt, and control
 on both sides of the keyboard, and hitting an invalid sysrq sequence again
 will fix the problem. (ie, something like alt-sysrq-z). Switching to another
 virtual console (ALT+Fn) and then back again should also help.
 
-*  I hit SysRQ, but nothing seems to happen, what's wrong?
+*  I hit SysRq, but nothing seems to happen, what's wrong?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There are some keyboards that send different scancodes for SysRQ than the
-pre-defined 0x54. So if SysRQ doesn't work out of the box for a certain 
-keyboard, run 'showkey -s' to find out the proper scancode sequence. Then 
-use 'setkeycodes <sequence> 84' to define this sequence to the usual SysR
+There are some keyboards that send different scancodes for SysRq than the
+pre-defined 0x54. So if SysRq doesn't work out of the box for a certain
+keyboard, run 'showkey -s' to find out the proper scancode sequence. Then
+use 'setkeycodes <sequence> 84' to define this sequence to the usual SysRq
 code (84 is decimal for 0x54). It's probably best to put this command in a
-boot script. Oh, and by the way, you exit 'showkey' by not typing anything 
+boot script. Oh, and by the way, you exit 'showkey' by not typing anything
 for ten seconds.
 
+*  I want to add SysRQ key events to a module, how does it work?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In order to register a basic function with the table, you must first include
+the header 'include/linux/sysrq.h', this will define everything else you need.
+Next, you must create a sysrq_key_op struct, and populate it with A) the key
+handler function you will use, B) a help_msg string, that will print when SysRQ
+prints help, and C) an action_msg string, that will print right before your
+handler is called. Your handler must conform to the protoype in 'sysrq.h'.
+
+After the sysrq_key_op is created, you can call the macro 
+register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in
+sysrq.h, this will register the operation pointed to by 'op_p' at table
+key 'key', if that slot in the table is blank. At module unload time, you must
+call the macro unregister_sysrq_key(int key, struct sysrq_key_op *op_p), which
+will remove the key op pointed to by 'op_p' from the key 'key', if and only if
+it is currently registered in that slot. This is in case the slot has been
+overwritten since you registered it.
+
+The Magic SysRQ system works by registering key operations against a key op
+lookup table, which is defined in 'drivers/char/sysrq.c'. This key table has
+a number of operations registered into it at compile time, but is mutable,
+and 4 functions are exported for interface to it: __sysrq_lock_table,
+__sysrq_unlock_table, __sysrq_get_key_op, and __sysrq_put_key_op. The
+functions __sysrq_swap_key_ops and __sysrq_swap_key_ops_nolock are defined
+in the header itself, and the REGISTER and UNREGISTER macros are built fromi
+these. More complex (and dangerous!) manipulations of the table are possible
+using these functions, but you must be careful to always lock the table before
+you read or write from it, and to unlock it again when you are done. (And of
+course, to never ever leave an invalid pointer in the table). Null pointers in
+the table are always safe :)
+
+If for some reason you feel the need to call the handle_sysrq function from
+within a function called by handle_sysrq, you must be aware that you are in
+a lock (you are also in an interupt handler, which means don't sleep!), so
+you must call __handle_sysrq_nolock instead.
+
 *  I have more questions, who can I ask?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 You may feel free to send email to myrdraal@deathsdoor.com, and I will
-respond as soon as possible. 
+respond as soon as possible.
  -Myrdraal
 
+And I'll answer any questions about the registration system you got, also
+responding as soon as possible.
+ -Crutcher
+
 *  Credits
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Written by Mydraal <myrdraal@deathsdoor.com>
 Updated by Adam Sulmicki <adam@cfar.umd.edu>
+Updated by Jeremy M. Dolan <jmd@turbogeek.org> 2001/01/28 10:15:59
+Added to by Crutcher Dunnavant <crutcher+kernel@datastacks.com>
index b0dacf88eaf33f5f838f6b6a806fc0a47d264691..45314f823c90166a484ae05089f6724f9cdcc253 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 10
-EXTRAVERSION =-pre11
+EXTRAVERSION =-pre12
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -228,7 +228,9 @@ MRPROPER_FILES = \
        .menuconfig.log \
        include/asm \
        .hdepend scripts/mkdep scripts/split-include scripts/docproc \
-       $(TOPDIR)/include/linux/modversions.h
+       $(TOPDIR)/include/linux/modversions.h \
+       kernel.spec
+
 # directories removed with 'make mrproper'
 MRPROPER_DIRS = \
        include/config \
@@ -252,7 +254,7 @@ Version: dummy
 boot: vmlinux
        @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot
 
-vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
+vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
        $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
                --start-group \
                $(CORE_FILES) \
@@ -297,11 +299,7 @@ $(TOPDIR)/include/linux/version.h: include/linux/version.h
 $(TOPDIR)/include/linux/compile.h: include/linux/compile.h
 
 newversion:
-       @if [ ! -f .version ]; then \
-               echo 1 > .version; \
-       else \
-               expr 0`cat .version` + 1 > .version; \
-       fi
+       . scripts/mkversion > .version
 
 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
        @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver
@@ -423,7 +421,8 @@ mrproper: clean archmrproper
        $(MAKE) -C Documentation/DocBook mrproper
 
 distclean: mrproper
-       rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+       rm -f core `find . \( -not -type d \) -and \
+               \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
                -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
                -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
 
@@ -506,3 +505,30 @@ scripts/mkdep: scripts/mkdep.c
 
 scripts/split-include: scripts/split-include.c
        $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c
+
+#
+# RPM target
+#
+#      If you do a make spec before packing the tarball you can rpm -ta it
+#
+spec:
+       . scripts/mkspec >kernel.spec
+
+#
+#      Build a tar ball, generate an rpm from it and pack the result
+#      There arw two bits of magic here
+#      1) The use of /. to avoid tar packing just the symlink
+#      2) Removing the .dep files as they have source paths in them that
+#         will become invalid
+#
+rpm:   clean spec
+       find . \( -size 0 -o -name .depend -o -name .hdepend \) -type f -print | xargs rm -f
+       set -e; \
+       cd $(TOPDIR)/.. ; \
+       ln -sf $(TOPDIR) $(KERNELPATH) ; \
+       tar -cvz --exclude CVS -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \
+       rm $(KERNELPATH) ; \
+       cd $(TOPDIR) ; \
+       . scripts/mkversion > .version ; \
+       rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
+       rm $(TOPDIR)/../$(KERNELPATH).tar.gz
index 3bd4e566b35548374a719f154e05b4659b59927d..103c2abe0beeb9df6947ed57721cffc7d4a64650 100644 (file)
@@ -233,6 +233,16 @@ ptrace_cancel_bpt(struct task_struct * child)
        return (nsaved != 0);
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{ 
+       ptrace_cancel_bpt(child);
+}
+
 asmlinkage long
 sys_ptrace(long request, long pid, long addr, long data,
           int a4, int a5, struct pt_regs regs)
@@ -362,21 +372,8 @@ sys_ptrace(long request, long pid, long addr, long data,
                ret = 0;
                goto out;
 
-       case PTRACE_DETACH: /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       goto out;
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               wake_up_process(child);
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               /* make sure single-step breakpoint is gone. */
-               ptrace_cancel_bpt(child);
-               ret = 0;
+       case PTRACE_DETACH:      /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
                goto out;
 
        default:
index 16c77f0ba3c0b54a42406f70714cfa108aae33d3..5b23dc653be173c10ef9007463111c5f8af13d0c 100644 (file)
@@ -386,6 +386,16 @@ void __ptrace_cancel_bpt(struct task_struct *child)
        }
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       __ptrace_cancel_bpt(child);
+}
+
 static int do_ptrace(int request, struct task_struct *child, long addr, long data)
 {
        unsigned long tmp;
@@ -491,20 +501,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat
                 * detach a process that was attached.
                 */
                case PTRACE_DETACH:
-                       ret = -EIO;
-                       if ((unsigned long) data > _NSIG)
-                               break;
-                       child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-                       child->exit_code = data;
-                       write_lock_irq(&tasklist_lock);
-                       REMOVE_LINKS(child);
-                       child->p_pptr = child->p_opptr;
-                       SET_LINKS(child);
-                       write_unlock_irq(&tasklist_lock);
-                       /* make sure single-step breakpoint is gone. */
-                       __ptrace_cancel_bpt(child);
-                       wake_up_process (child);
-                       ret = 0;
+                       ret = ptrace_detach(child, data);
                        break;
 
                /*
index 37912fd9c1922048d05abf73069ca7fd2f9ca21b..9bd35f605a455b13391aaee09ced89c01d0bb262 100644 (file)
@@ -82,6 +82,16 @@ static inline int put_reg(struct task_struct *task, unsigned int regno,
        return 0;
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* Todo - pending singlesteps? */
+}
+
 /* Note that this implementation of ptrace behaves differently from vanilla
  * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
  * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
@@ -245,24 +255,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        break;
                }
 
-               case PTRACE_DETACH: { /* detach a process that was attached. */
-                       long tmp;
-
-                       ret = -EIO;
-                       if ((unsigned long) data > _NSIG)
-                               break;
-                       child->ptrace &= ~(PT_PTRACED | PT_TRACESYS);
-                       child->exit_code = data;
-                       write_lock_irq(&tasklist_lock);
-                       REMOVE_LINKS(child);
-                       child->p_pptr = child->p_opptr;
-                       SET_LINKS(child);
-                       write_unlock_irq(&tasklist_lock);
-                       /* TODO: make sure any pending breakpoint is killed */
-                       wake_up_process(child);
-                       ret = 0;
+               case PTRACE_DETACH:
+                       ret = ptrace_detach(child, data);
                        break;
-               }
 
                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                        int i;
index 99d309aa89971d6dfbc156b2eae772e060ce93bb..d3ef1ed5e4a2a37a1b33529782e2a2ee0b56cd22 100644 (file)
@@ -186,7 +186,10 @@ mainmenu_option next_comment
 comment 'General setup'
 
 bool 'Networking support' CONFIG_NET
-bool 'SGI Visual Workstation support' CONFIG_VISWS
+
+# Visual Workstation support is utterly broken.
+# If you want to see it working mail an VW540 to hch@infradead.org 8)
+#bool 'SGI Visual Workstation support' CONFIG_VISWS
 if [ "$CONFIG_VISWS" = "y" ]; then
    define_bool CONFIG_X86_VISWS_APIC y
    define_bool CONFIG_X86_LOCAL_APIC y
@@ -388,6 +391,13 @@ fi
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+fi
+
 endmenu
index 4d8b92956441ec11e541269aa7f252a493328eb8..9c8a891632cc096b99681840209cf6583efbf4d4 100644 (file)
@@ -65,7 +65,6 @@ CONFIG_HAVE_DEC_LOCK=y
 # General setup
 #
 CONFIG_NET=y
-# CONFIG_VISWS is not set
 CONFIG_X86_IO_APIC=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_PCI=y
@@ -255,6 +254,9 @@ CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
 
 #
 # SCSI support
@@ -378,7 +380,6 @@ 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
@@ -400,8 +401,6 @@ CONFIG_NET_PCI=y
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
@@ -428,9 +427,9 @@ CONFIG_EEPRO100=y
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
 # CONFIG_DL2K is not set
 # CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
@@ -468,6 +467,7 @@ CONFIG_PCMCIA_PCNET=y
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR is not set
+# CONFIG_PCMCIA_XIRCOM is not set
 # CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
 CONFIG_PCMCIA_RAYCS=y
@@ -774,4 +774,4 @@ CONFIG_USB_STORAGE=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
index 67872949d8d7deded644709d2dbf06f375dd1237..a1dc301ef83810932d9e36418faa74f6f59c9acc 100644 (file)
@@ -30,15 +30,15 @@ obj-y                       += pci-pc.o pci-irq.o
 endif
 endif
 
-obj-$(CONFIG_MCA)      += mca.o
-obj-$(CONFIG_MTRR)     += mtrr.o
-obj-$(CONFIG_X86_MSR)  += msr.o
-obj-$(CONFIG_X86_CPUID)        += cpuid.o
-obj-$(CONFIG_MICROCODE)        += microcode.o
-obj-$(CONFIG_APM)      += apm.o
-obj-$(CONFIG_SMP)      += smp.o smpboot.o trampoline.o
-obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o
-obj-$(CONFIG_X86_IO_APIC)      += io_apic.o mpparse.o
+obj-$(CONFIG_MCA)              += mca.o
+obj-$(CONFIG_MTRR)             += mtrr.o
+obj-$(CONFIG_X86_MSR)          += msr.o
+obj-$(CONFIG_X86_CPUID)                += cpuid.o
+obj-$(CONFIG_MICROCODE)                += microcode.o
+obj-$(CONFIG_APM)              += apm.o
+obj-$(CONFIG_SMP)              += smp.o smpboot.o trampoline.o
+obj-$(CONFIG_X86_LOCAL_APIC)   += mpparse.o apic.o nmi.o
+obj-$(CONFIG_X86_IO_APIC)      += io_apic.o
 obj-$(CONFIG_X86_VISWS_APIC)   += visws_apic.o
 
 include $(TOPDIR)/Rules.make
index a6eb5dc18c6b1a66541b9b7a69f6d58d82bc7a76..d58ae186a7b026ade28adebb76e979d0b61f7088 100644 (file)
@@ -9,6 +9,7 @@
  *                                     and Rolf G. Tews
  *                                     for testing these extensively.
  *     Maciej W. Rozycki       :       Various updates and fixes.
+ *     Mikael Pettersson       :       Power Management for UP-APIC.
  */
 
 #include <linux/config.h>
@@ -29,6 +30,9 @@
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
 
+/* Using APIC to generate smp_local_timer_interrupt? */
+int using_apic_timer = 0;
+
 int prof_multiplier[NR_CPUS] = { 1, };
 int prof_old_multiplier[NR_CPUS] = { 1, };
 int prof_counter[NR_CPUS] = { 1, };
@@ -90,10 +94,10 @@ void __init connect_bsp_APIC(void)
                 */
                clear_local_APIC();
                /*
-                * PIC mode, enable symmetric IO mode in the IMCR,
-                * i.e. connect BSP's local APIC to INT and NMI lines.
+                * PIC mode, enable APIC mode in the IMCR, i.e.
+                * connect BSP's local APIC to INT and NMI lines.
                 */
-               printk("leaving PIC mode, enabling symmetric IO mode.\n");
+               printk("leaving PIC mode, enabling APIC mode.\n");
                outb(0x70, 0x22);
                outb(0x01, 0x23);
        }
@@ -108,7 +112,7 @@ void disconnect_bsp_APIC(void)
                 * interrupts, including IPIs, won't work beyond
                 * this point!  The only exception are INIT IPIs.
                 */
-               printk("disabling symmetric IO mode, entering PIC mode.\n");
+               printk("disabling APIC mode, entering PIC mode.\n");
                outb(0x70, 0x22);
                outb(0x00, 0x23);
        }
@@ -125,7 +129,7 @@ void disable_local_APIC(void)
         * for 82489DX!).
         */
        value = apic_read(APIC_SPIV);
-       value &= ~(1<<8);
+       value &= ~APIC_SPIV_APIC_ENABLED;
        apic_write_around(APIC_SPIV, value);
 }
 
@@ -204,6 +208,48 @@ void __init sync_Arb_IDs(void)
 
 extern void __error_in_apic_c (void);
 
+/*
+ * An initial setup of the virtual wire mode.
+ */
+void __init init_bsp_APIC(void)
+{
+       unsigned long value, ver;
+
+       /*
+        * Don't do the setup now if we have a SMP BIOS as the
+        * through-I/O-APIC virtual wire mode might be active.
+        */
+       if (smp_found_config || !cpu_has_apic)
+               return;
+
+       value = apic_read(APIC_LVR);
+       ver = GET_APIC_VERSION(value);
+
+       /*
+        * Do not trust the local APIC being empty at bootup.
+        */
+       clear_local_APIC();
+
+       /*
+        * Enable APIC.
+        */
+       value = apic_read(APIC_SPIV);
+       value &= ~APIC_VECTOR_MASK;
+       value |= APIC_SPIV_APIC_ENABLED;
+       value |= APIC_SPIV_FOCUS_DISABLED;
+       value |= SPURIOUS_APIC_VECTOR;
+       apic_write_around(APIC_SPIV, value);
+
+       /*
+        * Set up the virtual wire mode.
+        */
+       apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
+       value = APIC_DM_NMI;
+       if (!APIC_INTEGRATED(ver))              /* 82489DX */
+               value |= APIC_LVT_LEVEL_TRIGGER;
+       apic_write_around(APIC_LVT1, value);
+}
+
 void __init setup_local_APIC (void)
 {
        unsigned long value, ver, maxlvt;
@@ -256,7 +302,7 @@ void __init setup_local_APIC (void)
        /*
         * Enable APIC
         */
-       value |= (1<<8);
+       value |= APIC_SPIV_APIC_ENABLED;
 
        /*
         * Some unknown Intel IO/APIC (or APIC) errata is biting us with
@@ -279,10 +325,10 @@ void __init setup_local_APIC (void)
         */
 #if 1
        /* Enable focus processor (bit==0) */
-       value &= ~(1<<9);
+       value &= ~APIC_SPIV_FOCUS_DISABLED;
 #else
        /* Disable focus processor (bit==1) */
-       value |= (1<<9);
+       value |= APIC_SPIV_FOCUS_DISABLED;
 #endif
        /*
         * Set spurious IRQ vector
@@ -339,24 +385,250 @@ void __init setup_local_APIC (void)
                printk("ESR value after enabling vector: %08lx\n", value);
        } else
                printk("No ESR for 82489DX.\n");
+
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               setup_apic_nmi_watchdog();
 }
 
-void __init init_apic_mappings(void)
+#ifdef CONFIG_PM
+
+#include <linux/slab.h>
+#include <linux/pm.h>
+
+static struct {
+       /* 'active' is true if the local APIC was enabled by us and
+          not the BIOS; this signifies that we are also responsible
+          for disabling it before entering apm/acpi suspend */
+       int active;
+       /* 'perfctr_pmdev' is here because the current (2.4.1) PM
+          callback system doesn't handle hierarchical dependencies */
+       struct pm_dev *perfctr_pmdev;
+       /* r/w apic fields */
+       unsigned int apic_id;
+       unsigned int apic_taskpri;
+       unsigned int apic_ldr;
+       unsigned int apic_dfr;
+       unsigned int apic_spiv;
+       unsigned int apic_lvtt;
+       unsigned int apic_lvtpc;
+       unsigned int apic_lvt0;
+       unsigned int apic_lvt1;
+       unsigned int apic_lvterr;
+       unsigned int apic_tmict;
+       unsigned int apic_tdcr;
+} apic_pm_state;
+
+static void apic_pm_suspend(void *data)
 {
-       unsigned long apic_phys;
+       unsigned int l, h;
+       unsigned long flags;
 
-       if (smp_found_config) {
-               apic_phys = mp_lapic_addr;
-       } else {
+       if (apic_pm_state.perfctr_pmdev)
+               pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data);
+       apic_pm_state.apic_id = apic_read(APIC_ID);
+       apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
+       apic_pm_state.apic_ldr = apic_read(APIC_LDR);
+       apic_pm_state.apic_dfr = apic_read(APIC_DFR);
+       apic_pm_state.apic_spiv = apic_read(APIC_SPIV);
+       apic_pm_state.apic_lvtt = apic_read(APIC_LVTT);
+       apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
+       apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0);
+       apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1);
+       apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
+       apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
+       apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
+       __save_flags(flags);
+       __cli();
+       disable_local_APIC();
+       rdmsr(MSR_IA32_APICBASE, l, h);
+       l &= ~MSR_IA32_APICBASE_ENABLE;
+       wrmsr(MSR_IA32_APICBASE, l, h);
+       __restore_flags(flags);
+}
+
+static void apic_pm_resume(void *data)
+{
+       unsigned int l, h;
+       unsigned long flags;
+
+       __save_flags(flags);
+       __cli();
+       rdmsr(MSR_IA32_APICBASE, l, h);
+       l &= ~MSR_IA32_APICBASE_BASE;
+       l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+       wrmsr(MSR_IA32_APICBASE, l, h);
+       apic_write(APIC_ID, apic_pm_state.apic_id);
+       apic_write(APIC_DFR, apic_pm_state.apic_dfr);
+       apic_write(APIC_LDR, apic_pm_state.apic_ldr);
+       apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri);
+       apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
+       apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
+       apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
+       apic_write(APIC_ESR, 0);
+       apic_read(APIC_ESR);
+       apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);
+       apic_write(APIC_ESR, 0);
+       apic_read(APIC_ESR);
+       apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
+       apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
+       apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
+       apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
+       __restore_flags(flags);
+       if (apic_pm_state.perfctr_pmdev)
+               pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data);
+}
+
+static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+       switch (rqst) {
+       case PM_SUSPEND:
+               apic_pm_suspend(data);
+               break;
+       case PM_RESUME:
+               apic_pm_resume(data);
+               break;
+       }
+       return 0;
+}
+
+/* perfctr driver should call this instead of pm_register() */
+struct pm_dev *apic_pm_register(pm_dev_t type,
+                               unsigned long id,
+                               pm_callback callback)
+{
+       struct pm_dev *dev;
+
+       if (!apic_pm_state.active)
+               return pm_register(type, id, callback);
+       if (apic_pm_state.perfctr_pmdev)
+               return NULL;    /* we're busy */
+       dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+       if (dev) {
+               memset(dev, 0, sizeof(*dev));
+               dev->type = type;
+               dev->id = id;
+               dev->callback = callback;
+               apic_pm_state.perfctr_pmdev = dev;
+       }
+       return dev;
+}
+
+/* perfctr driver should call this instead of pm_unregister() */
+void apic_pm_unregister(struct pm_dev *dev)
+{
+       if (!apic_pm_state.active) {
+               pm_unregister(dev);
+       } else if (dev == apic_pm_state.perfctr_pmdev) {
+               apic_pm_state.perfctr_pmdev = NULL;
+               kfree(dev);
+       }
+}
+
+static void __init apic_pm_init1(void)
+{
+       /* can't pm_register() at this early stage in the boot process
+          (causes an immediate reboot), so just set the flag */
+       apic_pm_state.active = 1;
+}
+
+static void __init apic_pm_init2(void)
+{
+       if (apic_pm_state.active)
+               pm_register(PM_SYS_DEV, 0, apic_pm_callback);
+}
+
+#else  /* CONFIG_PM */
+
+static inline void apic_pm_init1(void) { }
+static inline void apic_pm_init2(void) { }
+
+#endif /* CONFIG_PM */
+
+/*
+ * Detect and enable local APICs on non-SMP boards.
+ * Original code written by Keir Fraser.
+ */
+
+static int __init detect_init_APIC (void)
+{
+       u32 h, l, features;
+       int needs_pm = 0;
+       extern void get_cpu_vendor(struct cpuinfo_x86*);
+
+       /* Workaround for us being called before identify_cpu(). */
+       get_cpu_vendor(&boot_cpu_data);
+
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+               if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
+                       break;
+               goto no_apic;
+       case X86_VENDOR_INTEL:
+               if (boot_cpu_data.x86 == 6 ||
+                   (boot_cpu_data.x86 == 5 && cpu_has_apic))
+                       break;
+               goto no_apic;
+       default:
+               goto no_apic;
+       }
+
+       if (!cpu_has_apic) {
                /*
-                * set up a fake all zeroes page to simulate the
-                * local APIC and another one for the IO-APIC. We
-                * could use the real zero-page, but it's safer
-                * this way if some buggy code writes to this page ...
+                * Some BIOSes disable the local APIC in the
+                * APIC_BASE MSR. This can only be done in
+                * software for Intel P6 and AMD K7 (Model > 1).
                 */
+               rdmsr(MSR_IA32_APICBASE, l, h);
+               if (!(l & MSR_IA32_APICBASE_ENABLE)) {
+                       printk("Local APIC disabled by BIOS -- reenabling.\n");
+                       l &= ~MSR_IA32_APICBASE_BASE;
+                       l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+                       wrmsr(MSR_IA32_APICBASE, l, h);
+                       needs_pm = 1;
+               }
+       }
+       /*
+        * The APIC feature bit should now be enabled
+        * in `cpuid'
+        */
+       features = cpuid_edx(1);
+       if (!(features & (1 << X86_FEATURE_APIC))) {
+               printk("Could not enable APIC!\n");
+               return -1;
+       }
+       set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);
+       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+       boot_cpu_id = 0;
+       if (nmi_watchdog != NMI_NONE)
+               nmi_watchdog = NMI_LOCAL_APIC;
+
+       printk("Found and enabled local APIC!\n");
+
+       if (needs_pm)
+               apic_pm_init1();
+
+       return 0;
+
+no_apic:
+       printk("No local APIC present or hardware disabled\n");
+       return -1;
+}
+
+void __init init_apic_mappings(void)
+{
+       unsigned long apic_phys;
+
+       /*
+        * If no local APIC can be found then set up a fake all
+        * zeroes page to simulate the local APIC and another
+        * one for the IO-APIC.
+        */
+       if (!smp_found_config && detect_init_APIC()) {
                apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
                apic_phys = __pa(apic_phys);
-       }
+       } else
+               apic_phys = mp_lapic_addr;
+
        set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
        Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
 
@@ -603,6 +875,9 @@ static unsigned int calibration_result;
 
 void __init setup_APIC_clocks (void)
 {
+       printk("Using local APIC timer interrupts.\n");
+       using_apic_timer = 1;
+
        __cli();
 
        calibration_result = calibrate_APIC_clock();
@@ -790,3 +1065,43 @@ asmlinkage void smp_error_interrupt(void)
                smp_processor_id(), v , v1);
 }
 
+/*
+ * This initializes the IO-APIC and APIC hardware if this is
+ * a UP kernel.
+ */
+int __init APIC_init_uniprocessor (void)
+{
+       if (!smp_found_config && !cpu_has_apic)
+               return -1;
+
+       /*
+        * Complain if the BIOS pretends there is one.
+        */
+       if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
+               printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
+                       boot_cpu_id);
+               return -1;
+       }
+
+       verify_local_APIC();
+
+       connect_bsp_APIC();
+
+       phys_cpu_present_map = 1;
+       apic_write_around(APIC_ID, boot_cpu_id);
+
+       apic_pm_init2();
+
+       setup_local_APIC();
+
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               check_nmi_watchdog();
+#ifdef CONFIG_X86_IO_APIC
+       if (smp_found_config)
+               if (!skip_ioapic_setup && nr_ioapics)
+                       setup_IO_APIC();
+#endif
+       setup_APIC_clocks();
+
+       return 0;
+}
index 9dd0328eef2757ac1dae930f15894f23182ba614..922c629232618f0c9ec66fff66b33584a2a7a974 100644 (file)
  *   1.14: Make connection version persist across module unload/load.
  *         Enable and engage power management earlier.
  *         Disengage power management on module unload.
+ *         Changed to use the sysrq-register hack for registering the
+ *         power off function called by magic sysrq based upon discussions
+ *         in irc://irc.openprojects.net/#kernelnewbies
+ *         (Crutcher Dunnavant <crutcher+kernel@datastacks.com>).
  *         Make CONFIG_APM_REAL_MODE_POWER_OFF run time configurable.
  *         (Arjan van de Ven <arjanv@redhat.com>) modified by sfr.
  *         Work around byte swap bug in one of the Vaio's BIOS's
 #include <asm/uaccess.h>
 #include <asm/desc.h>
 
+#include <linux/sysrq.h>
+
 extern unsigned long get_cmos_time(void);
 extern void machine_real_restart(unsigned char *, int);
 
-#ifdef CONFIG_MAGIC_SYSRQ
-extern void (*sysrq_power_off)(void);
-#endif
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 extern int (*console_blank_hook)(int);
 #endif
@@ -686,6 +689,23 @@ static void apm_power_off(void)
                (void) apm_set_power_state(APM_STATE_OFF);
 }
 
+#ifdef CONFIG_MAGIC_SYSRQ
+/*
+ * Magic sysrq key and handler for the power off function
+ */
+
+void handle_poweroff (int key, struct pt_regs *pt_regs,
+                                       struct kbd_struct *kbd, struct tty_struct *tty) {
+               apm_power_off();
+}
+struct sysrq_key_op sysrq_poweroff_op = {
+       handler:        handle_poweroff,
+       help_msg:       "Off",
+       action_msg:     "Power Off\n"
+};
+#endif
+
+
 #ifdef CONFIG_APM_DO_ENABLE
 static int apm_enable_power_management(int enable)
 {
@@ -1544,9 +1564,8 @@ static int apm(void *unused)
        /* Install our power off handler.. */
        if (power_off)
                pm_power_off = apm_power_off;
-#ifdef CONFIG_MAGIC_SYSRQ
-       sysrq_power_off = apm_power_off;
-#endif
+       register_sysrq_key('o',&sysrq_poweroff_op);
+
        if (smp_num_cpus == 1) {
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
                console_blank_hook = apm_console_blank;
@@ -1761,9 +1780,7 @@ static void __exit apm_exit(void)
        }
        misc_deregister(&apm_device);
        remove_proc_entry("apm", NULL);
-#ifdef CONFIG_MAGIC_SYSRQ
-       sysrq_power_off = NULL;
-#endif
+       unregister_sysrq_key('o',&sysrq_poweroff_op);
        if (power_off)
                pm_power_off = NULL;
        exit_kapmd = 1;
index f4824555accf021359ce3702dd8e0e68a86d151f..fb47c8a968f7e1a61b589c8303e39ffa2b8da402 100644 (file)
@@ -6,6 +6,9 @@
 #include <linux/apm_bios.h>
 #include <linux/slab.h>
 #include <asm/io.h>
+#include <linux/pm.h>
+#include <linux/keyboard.h>
+#include <asm/keyboard.h>
 
 struct dmi_header
 {
@@ -87,7 +90,15 @@ int __init dmi_iterate(void (*decode)(struct dmi_header *))
        unsigned char buf[20];
        long fp=0xE0000L;
        fp -= 16;
-       
+
+#ifdef CONFIG_SIMNOW
+       /*
+        *      Skip on x86/64 with simnow. Will eventually go away
+        *      If you see this ifdef in 2.6pre mail me !
+        */
+       return;
+#endif
+       
        while( fp < 0xFFFFF)
        {
                fp+=16;
@@ -190,6 +201,11 @@ static __init int disable_ide_dma(struct dmi_blacklist *d)
        return 0;
 }
 
+/* 
+ * Reboot options and system auto-detection code provided by
+ * Dell Computer Corporation so their systems "just work". :-)
+ */
+
 /* 
  * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
  */
@@ -204,6 +220,32 @@ static __init int set_bios_reboot(struct dmi_blacklist *d)
        return 0;
 }
 
+/*
+ * Some machines require the "reboot=s"  commandline option, this quirk makes that automatic.
+ */
+static __init int set_smp_reboot(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_SMP
+       extern int reboot_smp;
+       if (reboot_smp == 0)
+       {
+               reboot_smp = 1;
+               printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
+       }
+#endif
+       return 0;
+}
+
+/*
+ * Some machines require the "reboot=b,s"  commandline option, this quirk makes that automatic.
+ */
+static __init int set_smp_bios_reboot(struct dmi_blacklist *d)
+{
+       set_smp_reboot(d);
+       set_bios_reboot(d);
+       return 0;
+}
+
 /*
  * Some bioses have a broken protected mode poweroff and need to use realmode
  */
@@ -271,6 +313,27 @@ static __init int broken_apm_power(struct dmi_blacklist *d)
        return 0;
 }              
 
+#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
+/*
+ * Check for a Sony Vaio system in order to enable the use of
+ * the sonypi driver (we don't want this driver to be used on
+ * other systems, even if they have the good PCI IDs).
+ *
+ * This one isn't a bug detect for those who asked, we simply want to
+ * activate Sony specific goodies like the camera and jogdial..
+ */
+int is_sony_vaio_laptop;
+
+static __init int sony_vaio_laptop(struct dmi_blacklist *d)
+{
+       if (is_sony_vaio_laptop == 0)
+       {
+               is_sony_vaio_laptop = 1;
+               printk(KERN_INFO "%s laptop detected.\n", d->ident);
+       }
+       return 0;
+}
+#endif
 
 /*
  * This bios swaps the APM minute reporting bytes over (Many sony laptops
@@ -283,6 +346,46 @@ static __init int swab_apm_power_in_minutes(struct dmi_blacklist *d)
        printk(KERN_WARNING "BIOS strings suggest APM reports battery life in minutes and wrong byte order.\n");
        return 0;
 }
+
+/*
+ * The Intel 440GX hall of shame. 
+ *
+ * On many (all we have checked) of these boxes the $PIRQ table is wrong.
+ * The MP1.4 table is right however and so SMP kernels tend to work. 
+ */
+static __init int broken_pirq(struct dmi_blacklist *d)
+{
+       printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
+       printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n");
+       printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
+       printk(KERN_INFO " *** contact your vendor and ask about updates.\n");
+       printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
+       return 0;
+}
+
+/*
+ * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it
+ * was disabled before the suspend. Linux gets terribly confused by that.
+ */
+
+typedef void (pm_kbd_func) (void);
+extern pm_kbd_func *pm_kbd_request_override;
+
+static __init int broken_ps2_resume(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_VT
+       if (pm_kbd_request_override == NULL)
+       {
+               pm_kbd_request_override = pckbd_pm_resume;
+               printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround enabled.\n", d->ident);
+       }
+#endif 
+       return 0;
+}
+
+
+
 /*
  *     Process the DMI blacklists
  */
@@ -300,6 +403,11 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
                        NO_MATCH, NO_MATCH, NO_MATCH
                        } },
 #endif                 
+       { broken_ps2_resume, "Dell Latitude C600", {    /* Handle problems with APM on the C600 */
+                       MATCH(DMI_SYS_VENDOR, "Dell"),
+                       MATCH(DMI_PRODUCT_NAME, "Latitude C600"),
+                       NO_MATCH, NO_MATCH
+                       } },
        { broken_apm_power, "Dell Inspiron 5000e", {    /* Handle problems with APM on Inspiron 5000e */
                        MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
                        MATCH(DMI_BIOS_VERSION, "A04"),
@@ -310,14 +418,14 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
                        MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
                        MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
                        } },
-       { set_bios_reboot, "PowerEdge 1300/500", {      /* Handle problems with rebooting on Dell 1300's */
+       { set_smp_bios_reboot, "Dell PowerEdge 1300", { /* Handle problems with rebooting on Dell 1300's */
                        MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
-                       MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/500"),
+                       MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
                        NO_MATCH, NO_MATCH
                        } },
-       { set_bios_reboot, "PowerEdge 1300/550", {      /* Handle problems with rebooting on Dell 1300's */
+       { set_bios_reboot, "Dell PowerEdge 300", {      /* Handle problems with rebooting on Dell 1300's */
                        MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
-                       MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/550"),
+                       MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
                        NO_MATCH, NO_MATCH
                        } },
        { set_apm_ints, "IBM", {        /* Allow interrupts during suspend on IBM laptops */
@@ -329,6 +437,12 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
                        MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"),
                        NO_MATCH, NO_MATCH
                        } },
+       { set_apm_ints, "Compaq 12XL125", {     /* Allow interrupts during suspend on Compaq Laptops*/
+                       MATCH(DMI_SYS_VENDOR, "Compaq"),
+                       MATCH(DMI_PRODUCT_NAME, "Compaq PC"),
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION,"4.06")
+                       } },
        { set_apm_ints, "ASUSTeK", {   /* Allow interrupts during APM or the clock goes slow */
                        MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
                        MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"),
@@ -339,21 +453,97 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
                        MATCH(DMI_PRODUCT_NAME, "Delhi3"),
                        NO_MATCH, NO_MATCH,
                        } },
-       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-Z505LS */
+       { apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
+                       MATCH(DMI_SYS_VENDOR, "SHARP"),
+                       MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
+                       MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
+                       MATCH(DMI_BIOS_VERSION,"Version R2.08")
+                       } },
+#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
+       { sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
+                       MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       MATCH(DMI_PRODUCT_NAME, "PCG-"),
+                       NO_MATCH, NO_MATCH,
+                       } },
+#endif
+       { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */
                        MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
-                       MATCH(DMI_BIOS_VERSION, "R0203Z3"),
-                       MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH
+                       MATCH(DMI_BIOS_VERSION, "R0206H"),
+                       MATCH(DMI_BIOS_DATE, "08/23/99"), NO_MATCH
+       } },
+
+       { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505VX */
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION, "W2K06H0"),
+                       MATCH(DMI_BIOS_DATE, "02/03/00"), NO_MATCH
                        } },
-       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-Z505LS */
+                       
+       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-XG29 */
                        MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
-                       MATCH(DMI_BIOS_VERSION, "R0203D0"),
-                       MATCH(DMI_BIOS_DATE, "05/12/00"), NO_MATCH
+                       MATCH(DMI_BIOS_VERSION, "R0117A0"),
+                       MATCH(DMI_BIOS_DATE, "04/25/00"), NO_MATCH
                        } },
+
        { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-Z600NE */
                        MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
                        MATCH(DMI_BIOS_VERSION, "R0121Z1"),
                        MATCH(DMI_BIOS_DATE, "05/11/00"), NO_MATCH
                        } },
+
+       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-Z505LS */
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION, "R0203D0"),
+                       MATCH(DMI_BIOS_DATE, "05/12/00"), NO_MATCH
+                       } },
+
+       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-Z505LS */
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION, "R0203Z3"),
+                       MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH
+                       } },
+       
+       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-F104K */
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION, "R0204K2"),
+                       MATCH(DMI_BIOS_DATE, "08/28/00"), NO_MATCH
+                       } },
+       
+       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-C1VN/C1VE */
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION, "R0208P1"),
+                       MATCH(DMI_BIOS_DATE, "11/09/00"), NO_MATCH
+                       } },
+       { swab_apm_power_in_minutes, "Sony VAIO", {     /* Handle problems with APM on Sony Vaio PCG-C1VE */
+                       MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       MATCH(DMI_BIOS_VERSION, "R0204P1"),
+                       MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
+                       } },
+
+       /* Problem Intel 440GX bioses */
+
+       { broken_pirq, "SABR1 Bios", {                  /* Bad $PIR */
+                       MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
+                       MATCH(DMI_BIOS_VERSION,"SABR1"),
+                       NO_MATCH, NO_MATCH
+                       } },
+       { broken_pirq, "l44GX Bios", {                  /* Bad $PIR */
+                       MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
+                       MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
+                       NO_MATCH, NO_MATCH
+                        } },
+       { broken_pirq, "l44GX Bios", {          /* Bad $PIR */
+                       MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
+                       MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
+                       NO_MATCH, NO_MATCH
+                       } },
+                        
+       /* Intel in disgiuse - In this case they can't hide and they don't run
+          too well either... */
+       { broken_pirq, "Dell PowerEdge 8450", {         /* Bad $PIR */
+                       MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"),
+                       NO_MATCH, NO_MATCH, NO_MATCH
+                       } },
+
        { NULL, }
 };
        
index ef3fb15e7e7a796e761bb3f7e01dc91673a4698e..b4f342bb521f8979895552d8105dd2a37c76f3f6 100644 (file)
@@ -165,3 +165,13 @@ EXPORT_SYMBOL(empty_zero_page);
 #ifdef CONFIG_HAVE_DEC_LOCK
 EXPORT_SYMBOL(atomic_dec_and_lock);
 #endif
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
+
+#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
+extern int is_sony_vaio_laptop;
+EXPORT_SYMBOL(is_sony_vaio_laptop);
+#endif
+
index d7dffbd130fb20ed004c22c1b1f7325bee07fa03..0a4412a2fc02f301b076ea9921821b8ae6510e37 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
+#include <asm/apic.h>
 
 #include <linux/irq.h>
 
@@ -415,6 +416,9 @@ void __init init_ISA_irqs (void)
 {
        int i;
 
+#ifdef CONFIG_X86_LOCAL_APIC
+       init_bsp_APIC();
+#endif
        init_8259A(0);
 
        for (i = 0; i < NR_IRQS; i++) {
index bdff768554f7b50445f0924c17790c591e5aa794..840e90cffe85bc51df52b0664591cb216be3b0cf 100644 (file)
 #include <asm/smp.h>
 #include <asm/desc.h>
 
+#undef APIC_LOCKUP_DEBUG
+
 #define APIC_LOCKUP_DEBUG
 
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * # of IO-APICs and # of IRQ routing registers
+ * # of IRQ routing registers
  */
-int nr_ioapics;
 int nr_ioapic_registers[MAX_IO_APICS];
 
-/* I/O APIC entries */
-struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
-
-/* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
-
-/* MP IRQ source entries */
-int mp_irq_entries;
-
 #if CONFIG_SMP
 # define TARGET_CPUS cpu_online_map
 #else
@@ -754,11 +746,9 @@ void __init print_IO_APIC(void)
        printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
        printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.entries);
        if (    (reg_01.entries != 0x0f) && /* older (Neptune) boards */
-               (reg_01.entries != 0x11) &&
                (reg_01.entries != 0x17) && /* typical ISA+PCI boards */
                (reg_01.entries != 0x1b) && /* Compaq Proliant boards */
                (reg_01.entries != 0x1f) && /* dual Xeon boards */
-               (reg_01.entries != 0x20) &&
                (reg_01.entries != 0x22) && /* bigger Xeon boards */
                (reg_01.entries != 0x2E) &&
                (reg_01.entries != 0x3F)
@@ -769,7 +759,8 @@ void __init print_IO_APIC(void)
        if (    (reg_01.version != 0x01) && /* 82489DX IO-APICs */
                (reg_01.version != 0x10) && /* oldest IO-APICs */
                (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
-               (reg_01.version != 0x13)    /* Xeon IO-APICs */
+               (reg_01.version != 0x13) && /* Xeon IO-APICs */
+               (reg_01.entries != 0x20)    /* Intel P64H (82806 AA) */
        )
                UNEXPECTED_IO_APIC();
        if (reg_01.__reserved_1 || reg_01.__reserved_2)
@@ -820,7 +811,7 @@ void __init print_IO_APIC(void)
                        continue;
                printk(KERN_DEBUG "IRQ%d ", i);
                for (;;) {
-                       printk("-> %d", entry->pin);
+                       printk("-> %d:%d", entry->apic, entry->pin);
                        if (!entry->next)
                                break;
                        entry = irq_2_pin + entry->next;
@@ -1128,25 +1119,6 @@ static int __init timer_irq_works(void)
        return 0;
 }
 
-static int __init nmi_irq_works(void)
-{
-       irq_cpustat_t tmp[NR_CPUS];
-       int j, cpu;
-
-       memcpy(tmp, irq_stat, sizeof(tmp));
-       sti();
-       mdelay(50);
-
-       for (j = 0; j < smp_num_cpus; j++) {
-               cpu = cpu_logical_map(j);
-               if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 3) {
-                       printk(KERN_WARNING "CPU#%d NMI appears to be stuck.\n", cpu);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
 /*
  * In the SMP+IOAPIC case it might happen that there are an unspecified
  * number of pending IRQ events unhandled. These cases are very rare,
@@ -1236,6 +1208,7 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq)
 static void end_level_ioapic_irq (unsigned int irq)
 {
        unsigned long v;
+       int i;
 
 /*
  * It appears there is an erratum which affects at least version 0x11
@@ -1256,11 +1229,12 @@ static void end_level_ioapic_irq (unsigned int irq)
  * operation to prevent an edge-triggered interrupt escaping meanwhile.
  * The idea is from Manfred Spraul.  --macro
  */
-       v = apic_read(APIC_TMR + ((IO_APIC_VECTOR(irq) & ~0x1f) >> 1));
+       i = IO_APIC_VECTOR(irq);
+       v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 
        ack_APIC_irq();
 
-       if (!(v & (1 << (IO_APIC_VECTOR(irq) & 0x1f)))) {
+       if (!(v & (1 << (i & 0x1f)))) {
 #ifdef APIC_MISMATCH_DEBUG
                atomic_inc(&irq_mis_count);
 #endif
@@ -1524,7 +1498,7 @@ static inline void check_timer(void)
        pin1 = find_isa_irq_pin(0, mp_INT);
        pin2 = find_isa_irq_pin(0, mp_ExtINT);
 
-       printk(KERN_INFO "..TIMER: vector=%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
+       printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
 
        if (pin1 != -1) {
                /*
@@ -1532,11 +1506,11 @@ static inline void check_timer(void)
                 */
                unmask_IO_APIC_irq(0);
                if (timer_irq_works()) {
-                       if (nmi_watchdog) {
+                       if (nmi_watchdog == NMI_IO_APIC) {
                                disable_8259A_irq(0);
                                setup_nmi();
                                enable_8259A_irq(0);
-                               nmi_irq_works();
+                               check_nmi_watchdog();
                        }
                        return;
                }
@@ -1553,9 +1527,9 @@ static inline void check_timer(void)
                setup_ExtINT_IRQ0_pin(pin2, vector);
                if (timer_irq_works()) {
                        printk("works.\n");
-                       if (nmi_watchdog) {
+                       if (nmi_watchdog == NMI_IO_APIC) {
                                setup_nmi();
-                               nmi_irq_works();
+                               check_nmi_watchdog();
                        }
                        return;
                }
@@ -1636,19 +1610,3 @@ void __init setup_IO_APIC(void)
        check_timer();
        print_IO_APIC();
 }
-
-#ifndef CONFIG_SMP
-/*
- * This initializes the IO-APIC and APIC hardware if this is
- * a UP kernel.
- */
-void IO_APIC_init_uniprocessor (void)
-{
-       if (!smp_found_config)
-               return;
-       connect_bsp_APIC();
-       setup_local_APIC();
-       setup_IO_APIC();
-       setup_APIC_clocks();
-}
-#endif
index e2d7c385e212da98d7dddd7b983a794663f3e081..8f505502d6b84cc723d0f7c001ac43b450e826cb 100644 (file)
@@ -166,7 +166,7 @@ int get_irq_list(char *buf)
                p += sprintf(p, "%10u ",
                        nmi_count(cpu_logical_map(j)));
        p += sprintf(p, "\n");
-#if CONFIG_SMP
+#if CONFIG_X86_LOCAL_APIC
        p += sprintf(p, "LOC: ");
        for (j = 0; j < smp_num_cpus; j++)
                p += sprintf(p, "%10u ",
@@ -471,14 +471,15 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction *
  *     disable_irq_nosync - disable an irq without waiting
  *     @irq: Interrupt to disable
  *
- *     Disable the selected interrupt line. Disables of an interrupt
- *     stack. Unlike disable_irq(), this function does not ensure existing
+ *     Disable the selected interrupt line.  Disables and Enables are
+ *     nested.
+ *     Unlike disable_irq(), this function does not ensure existing
  *     instances of the IRQ handler have completed before returning.
  *
  *     This function may be called from IRQ context.
  */
  
-void inline disable_irq_nosync(unsigned int irq)
+inline void disable_irq_nosync(unsigned int irq)
 {
        irq_desc_t *desc = irq_desc + irq;
        unsigned long flags;
@@ -495,9 +496,9 @@ void inline disable_irq_nosync(unsigned int irq)
  *     disable_irq - disable an irq and wait for completion
  *     @irq: Interrupt to disable
  *
- *     Disable the selected interrupt line. Disables of an interrupt
- *     stack. That is for two disables you need two enables. This
- *     function waits for any pending IRQ handlers for this interrupt
+ *     Disable the selected interrupt line.  Enables and Disables are
+ *     nested.
+ *     This function waits for any pending IRQ handlers for this interrupt
  *     to complete before returning. If you use this function while
  *     holding a resource the IRQ handler may need you will deadlock.
  *
@@ -516,11 +517,12 @@ void disable_irq(unsigned int irq)
 }
 
 /**
- *     enable_irq - enable interrupt handling on an irq
+ *     enable_irq - enable handling of an irq
  *     @irq: Interrupt to enable
  *
- *     Re-enables the processing of interrupts on this IRQ line
- *     providing no disable_irq calls are now in effect.
+ *     Undoes the effect of one call to disable_irq().  If this
+ *     matches the last disable, processing of interrupts on this
+ *     IRQ line is re-enabled.
  *
  *     This function may be called from IRQ context.
  */
@@ -1027,20 +1029,9 @@ int setup_irq(unsigned int irq, struct irqaction * new)
 
 static struct proc_dir_entry * root_irq_dir;
 static struct proc_dir_entry * irq_dir [NR_IRQS];
-static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
-
-static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
 
 #define HEX_DIGITS 8
 
-static int irq_affinity_read_proc (char *page, char **start, off_t off,
-                       int count, int *eof, void *data)
-{
-       if (count < HEX_DIGITS+1)
-               return -EINVAL;
-       return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
-}
-
 static unsigned int parse_hex_value (const char *buffer,
                unsigned long count, unsigned long *ret)
 {
@@ -1078,6 +1069,19 @@ out:
        return 0;
 }
 
+#if CONFIG_SMP
+
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+       if (count < HEX_DIGITS+1)
+               return -EINVAL;
+       return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
 static int irq_affinity_write_proc (struct file *file, const char *buffer,
                                        unsigned long count, void *data)
 {
@@ -1089,7 +1093,6 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
 
        err = parse_hex_value(buffer, count, &new_value);
 
-#if CONFIG_SMP
        /*
         * Do not allow disabling IRQs completely - it's a too easy
         * way to make the system unusable accidentally :-) At least
@@ -1097,7 +1100,6 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
         */
        if (!(new_value & cpu_online_map))
                return -EINVAL;
-#endif
 
        irq_affinity[irq] = new_value;
        irq_desc[irq].handler->set_affinity(irq, new_value);
@@ -1105,6 +1107,8 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
        return full_count;
 }
 
+#endif
+
 static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
                        int count, int *eof, void *data)
 {
@@ -1132,7 +1136,6 @@ static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
 
 static void register_irq_proc (unsigned int irq)
 {
-       struct proc_dir_entry *entry;
        char name [MAX_NAMELEN];
 
        if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
@@ -1145,15 +1148,23 @@ static void register_irq_proc (unsigned int irq)
        /* create /proc/irq/1234 */
        irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
-       /* create /proc/irq/1234/smp_affinity */
-       entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+#if CONFIG_SMP
+       {
+               struct proc_dir_entry *entry;
 
-       entry->nlink = 1;
-       entry->data = (void *)(long)irq;
-       entry->read_proc = irq_affinity_read_proc;
-       entry->write_proc = irq_affinity_write_proc;
+               /* create /proc/irq/1234/smp_affinity */
+               entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
 
-       smp_affinity_entry[irq] = entry;
+               if (entry) {
+                       entry->nlink = 1;
+                       entry->data = (void *)(long)irq;
+                       entry->read_proc = irq_affinity_read_proc;
+                       entry->write_proc = irq_affinity_write_proc;
+               }
+
+               smp_affinity_entry[irq] = entry;
+       }
+#endif
 }
 
 unsigned long prof_cpu_mask = -1;
@@ -1169,6 +1180,9 @@ void init_irq_proc (void)
        /* create /proc/irq/prof_cpu_mask */
        entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
 
+       if (!entry)
+           return;
+
        entry->nlink = 1;
        entry->data = (void *)&prof_cpu_mask;
        entry->read_proc = prof_cpu_mask_read_proc;
index 25220e75cad3c096fd389619894b5ce5113bc48f..f0db48173c1e1a34d86e17f92a18b3ee7c2d5782 100644 (file)
@@ -38,6 +38,18 @@ int apic_version [MAX_APICS];
 int mp_bus_id_to_type [MAX_MP_BUSSES];
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
+
+/* I/O APIC entries */
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+
+/* # of MP IRQ source entries */
+struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+/* MP IRQ source entries */
+int mp_irq_entries;
+
+int nr_ioapics;
+
 int pic_mode;
 unsigned long mp_lapic_addr;
 
@@ -225,6 +237,11 @@ static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
                        MAX_IO_APICS, nr_ioapics);
                panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
        }
+       if (!m->mpc_apicaddr) {
+               printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
+                       " found in MP table, skipping!\n");
+               return;
+       }
        mp_ioapics[nr_ioapics] = *m;
        nr_ioapics++;
 }
@@ -365,10 +382,19 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
        return num_processors;
 }
 
+static int __init ELCR_trigger(unsigned int irq)
+{
+       unsigned int port;
+
+       port = 0x4d0 + (irq >> 3);
+       return (inb(port) >> (irq & 7)) & 1;
+}
+
 static void __init construct_default_ioirq_mptable(int mpc_default_type)
 {
        struct mpc_config_intsrc intsrc;
        int i;
+       int ELCR_fallback = 0;
 
        intsrc.mpc_type = MP_INTSRC;
        intsrc.mpc_irqflag = 0;                 /* conforming */
@@ -376,6 +402,26 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type)
        intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
 
        intsrc.mpc_irqtype = mp_INT;
+
+       /*
+        *  If true, we have an ISA/PCI system with no IRQ entries
+        *  in the MP table. To prevent the PCI interrupts from being set up
+        *  incorrectly, we try to use the ELCR. The sanity check to see if
+        *  there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can
+        *  never be level sensitive, so we simply see if the ELCR agrees.
+        *  If it does, we assume it's valid.
+        */
+       if (mpc_default_type == 5) {
+               printk("ISA/PCI bus type with no IRQ information... falling back to ELCR\n");
+
+               if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13))
+                       printk("ELCR contains invalid data... not using ELCR\n");
+               else {
+                       printk("Using ELCR to identify PCI interrupts\n");
+                       ELCR_fallback = 1;
+               }
+       }
+
        for (i = 0; i < 16; i++) {
                switch (mpc_default_type) {
                case 2:
@@ -387,6 +433,18 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type)
                                continue;       /* IRQ2 is never connected */
                }
 
+               if (ELCR_fallback) {
+                       /*
+                        *  If the ELCR indicates a level-sensitive interrupt, we
+                        *  copy that information over to the MP table in the
+                        *  irqflag field (level sensitive, active high polarity).
+                        */
+                       if (ELCR_trigger(i))
+                               intsrc.mpc_irqflag = 13;
+                       else
+                               intsrc.mpc_irqflag = 0;
+               }
+
                intsrc.mpc_srcbusirq = i;
                intsrc.mpc_dstirq = i ? i : 2;          /* IRQ0 to INTIN2 */
                MP_intsrc_info(&intsrc);
@@ -641,7 +699,7 @@ void __init find_visws_smp(void)
  */
 void __init find_smp_config (void)
 {
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
        find_intel_smp();
 #endif
 #ifdef CONFIG_VISWS
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
new file mode 100644 (file)
index 0000000..07571a2
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ *  linux/arch/i386/nmi.c
+ *
+ *  NMI watchdog support on APIC systems
+ *
+ *  Started by Ingo Molnar <mingo@redhat.com>
+ *
+ *  Fixes:
+ *  Mikael Pettersson  : AMD K7 support for local APIC NMI watchdog.
+ *  Mikael Pettersson  : Power Management for local APIC NMI watchdog.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/smp.h>
+#include <asm/mtrr.h>
+#include <asm/mpspec.h>
+
+unsigned int nmi_watchdog = NMI_NONE;
+static unsigned int nmi_hz = HZ;
+unsigned int nmi_perfctr_msr;  /* the MSR to reset in NMI handler */
+
+#define K7_EVNTSEL_ENABLE      (1 << 22)
+#define K7_EVNTSEL_INT         (1 << 20)
+#define K7_EVNTSEL_OS          (1 << 17)
+#define K7_EVNTSEL_USR         (1 << 16)
+#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING   0x76
+#define K7_NMI_EVENT           K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
+
+#define P6_EVNTSEL0_ENABLE     (1 << 22)
+#define P6_EVNTSEL_INT         (1 << 20)
+#define P6_EVNTSEL_OS          (1 << 17)
+#define P6_EVNTSEL_USR         (1 << 16)
+#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
+#define P6_NMI_EVENT           P6_EVENT_CPU_CLOCKS_NOT_HALTED
+
+int __init check_nmi_watchdog (void)
+{
+       irq_cpustat_t tmp[NR_CPUS];
+       int j, cpu;
+
+       printk(KERN_INFO "testing NMI watchdog ... ");
+
+       memcpy(tmp, irq_stat, sizeof(tmp));
+       sti();
+       mdelay((10*1000)/nmi_hz); // wait 10 ticks
+
+       for (j = 0; j < smp_num_cpus; j++) {
+               cpu = cpu_logical_map(j);
+               if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) {
+                       printk("CPU#%d: NMI appears to be stuck!\n", cpu);
+                       return -1;
+               }
+       }
+       printk("OK.\n");
+
+       /* now that we know it works we can reduce NMI frequency to
+          something more reasonable; makes a difference in some configs */
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               nmi_hz = 1;
+
+       return 0;
+}
+
+static int __init setup_nmi_watchdog(char *str)
+{
+       int nmi;
+
+       get_option(&str, &nmi);
+
+       if (nmi >= NMI_INVALID)
+               return 0;
+       if (nmi == NMI_NONE)
+               nmi_watchdog = nmi;
+       /*
+        * If any other x86 CPU has a local APIC, then
+        * please test the NMI stuff there and send me the
+        * missing bits. Right now Intel P6 and AMD K7 only.
+        */
+       if ((nmi == NMI_LOCAL_APIC) &&
+                       (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+                       (boot_cpu_data.x86 == 6))
+               nmi_watchdog = nmi;
+       if ((nmi == NMI_LOCAL_APIC) &&
+                       (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
+                       (boot_cpu_data.x86 == 6))
+               nmi_watchdog = nmi;
+       /*
+        * We can enable the IO-APIC watchdog
+        * unconditionally.
+        */
+       if (nmi == NMI_IO_APIC)
+               nmi_watchdog = nmi;
+       return 1;
+}
+
+__setup("nmi_watchdog=", setup_nmi_watchdog);
+
+#ifdef CONFIG_PM
+
+#include <linux/pm.h>
+
+struct pm_dev *nmi_pmdev;
+
+static void disable_apic_nmi_watchdog(void)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+               wrmsr(MSR_K7_EVNTSEL0, 0, 0);
+               break;
+       case X86_VENDOR_INTEL:
+               wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
+               break;
+       }
+}
+
+static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+       switch (rqst) {
+       case PM_SUSPEND:
+               disable_apic_nmi_watchdog();
+               break;
+       case PM_RESUME:
+               setup_apic_nmi_watchdog();
+               break;
+       }
+       return 0;
+}
+
+static void nmi_pm_init(void)
+{
+       if (!nmi_pmdev)
+               nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
+}
+
+#define __pminit       /*empty*/
+
+#else  /* CONFIG_PM */
+
+static inline void nmi_pm_init(void) { }
+
+#define __pminit       __init
+
+#endif /* CONFIG_PM */
+
+/*
+ * Activate the NMI watchdog via the local APIC.
+ * Original code written by Keith Owens.
+ */
+
+static void __pminit setup_k7_watchdog(void)
+{
+       int i;
+       unsigned int evntsel;
+
+       nmi_perfctr_msr = MSR_K7_PERFCTR0;
+
+       for(i = 0; i < 4; ++i) {
+               wrmsr(MSR_K7_EVNTSEL0+i, 0, 0);
+               wrmsr(MSR_K7_PERFCTR0+i, 0, 0);
+       }
+
+       evntsel = K7_EVNTSEL_INT
+               | K7_EVNTSEL_OS
+               | K7_EVNTSEL_USR
+               | K7_NMI_EVENT;
+
+       wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
+       Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+       wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
+       apic_write(APIC_LVTPC, APIC_DM_NMI);
+       evntsel |= K7_EVNTSEL_ENABLE;
+       wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
+}
+
+static void __pminit setup_p6_watchdog(void)
+{
+       int i;
+       unsigned int evntsel;
+
+       nmi_perfctr_msr = MSR_IA32_PERFCTR0;
+
+       for(i = 0; i < 2; ++i) {
+               wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0);
+               wrmsr(MSR_IA32_PERFCTR0+i, 0, 0);
+       }
+
+       evntsel = P6_EVNTSEL_INT
+               | P6_EVNTSEL_OS
+               | P6_EVNTSEL_USR
+               | P6_NMI_EVENT;
+
+       wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
+       Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+       wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
+       apic_write(APIC_LVTPC, APIC_DM_NMI);
+       evntsel |= P6_EVNTSEL0_ENABLE;
+       wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
+}
+
+void __pminit setup_apic_nmi_watchdog (void)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+               if (boot_cpu_data.x86 != 6)
+                       return;
+               setup_k7_watchdog();
+               break;
+       case X86_VENDOR_INTEL:
+               if (boot_cpu_data.x86 != 6)
+                       return;
+               setup_p6_watchdog();
+               break;
+       default:
+               return;
+       }
+       nmi_pm_init();
+}
+
+static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * the best way to detect whether a CPU has a 'hard lockup' problem
+ * is to check it's local APIC timer IRQ counts. If they are not
+ * changing then that CPU has some problem.
+ *
+ * as these watchdog NMI IRQs are generated on every CPU, we only
+ * have to check the current processor.
+ *
+ * since NMIs dont listen to _any_ locks, we have to be extremely
+ * careful not to rely on unsafe variables. The printk might lock
+ * up though, so we have to break up any console locks first ...
+ * [when there will be more tty-related locks, break them up
+ *  here too!]
+ */
+
+static unsigned int
+       last_irq_sums [NR_CPUS],
+       alert_counter [NR_CPUS];
+
+void touch_nmi_watchdog (void)
+{
+       int i;
+
+       /*
+        * Just reset the alert counters, (other CPUs might be
+        * spinning on locks we hold):
+        */
+       for (i = 0; i < smp_num_cpus; i++)
+               alert_counter[i] = 0;
+}
+
+void nmi_watchdog_tick (struct pt_regs * regs)
+{
+
+       /*
+        * Since current-> is always on the stack, and we always switch
+        * the stack NMI-atomically, it's safe to use smp_processor_id().
+        */
+       int sum, cpu = smp_processor_id();
+
+       sum = apic_timer_irqs[cpu];
+
+       if (last_irq_sums[cpu] == sum) {
+               /*
+                * Ayiee, looks like this CPU is stuck ...
+                * wait a few IRQs (5 seconds) before doing the oops ...
+                */
+               alert_counter[cpu]++;
+               if (alert_counter[cpu] == 5*nmi_hz) {
+                       spin_lock(&nmi_print_lock);
+                       /*
+                        * We are in trouble anyway, lets at least try
+                        * to get a message out.
+                        */
+                       bust_spinlocks(1);
+                       printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
+                       show_registers(regs);
+                       printk("console shuts up ...\n");
+                       console_silent();
+                       spin_unlock(&nmi_print_lock);
+                       bust_spinlocks(0);
+                       do_exit(SIGSEGV);
+               }
+       } else {
+               last_irq_sums[cpu] = sum;
+               alert_counter[cpu] = 0;
+       }
+       if (nmi_perfctr_msr)
+               wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+}
index 5ef93e608306cbc3d264cad4f4b323c4db89c26b..7d1635f2a31e9c35b147dd143b1baf6ddd0c98db 100644 (file)
@@ -154,6 +154,12 @@ static long no_idt[2];
 static int reboot_mode;
 int reboot_thru_bios;
 
+#ifdef CONFIG_SMP
+int reboot_smp = 0;
+static int reboot_cpu = -1;
+/* shamelessly grabbed from lib/vsprintf.c for readability */
+#define is_digit(c)    ((c) >= '0' && (c) <= '9')
+#endif
 static int __init reboot_setup(char *str)
 {
        while(1) {
@@ -170,6 +176,19 @@ static int __init reboot_setup(char *str)
                case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
                        reboot_thru_bios = 0;
                        break;
+#ifdef CONFIG_SMP
+               case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
+                       reboot_smp = 1;
+                       if (is_digit(*(str+1))) {
+                               reboot_cpu = (int) (*(str+1) - '0');
+                               if (is_digit(*(str+2))) 
+                                       reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
+                       }
+                               /* we will leave sorting out the final value 
+                               when we are ready to reboot, since we might not
+                               have set up boot_cpu_id or smp_num_cpu */
+                       break;
+#endif
                }
                if((str = strchr(str,',')) != NULL)
                        str++;
@@ -346,6 +365,34 @@ void machine_real_restart(unsigned char *code, int length)
 void machine_restart(char * __unused)
 {
 #if CONFIG_SMP
+       int cpuid;
+       
+       cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+       if (reboot_smp) {
+
+               /* check to see if reboot_cpu is valid 
+                  if its not, default to the BSP */
+               if ((reboot_cpu == -1) ||  
+                     (reboot_cpu > (NR_CPUS -1))  || 
+                     !(phys_cpu_present_map & (1<<cpuid))) 
+                       reboot_cpu = boot_cpu_id;
+
+               reboot_smp = 0;  /* use this as a flag to only go through this once*/
+               /* re-run this function on the other CPUs
+                  it will fall though this section since we have 
+                  cleared reboot_smp, and do the reboot if it is the
+                  correct CPU, otherwise it halts. */
+               if (reboot_cpu != cpuid)
+                       smp_call_function((void *)machine_restart , NULL, 1, 0);
+       }
+
+       /* if reboot_cpu is still -1, then we want a tradional reboot, 
+          and if we are not running on the reboot_cpu,, halt */
+       if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
+               for (;;)
+               __asm__ __volatile__ ("hlt");
+       }
        /*
         * Stop all CPUs and turn off local APICs and the IO-APIC, so
         * other OSs see a clean IRQ state.
index 716a08b6c57568398f2d94601fb4d45f81cb4a9d..a51cbf13be487922a4c47298ed02b2f6bac9e687 100644 (file)
@@ -134,6 +134,19 @@ static unsigned long getreg(struct task_struct *child,
        return retval;
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{ 
+       long tmp;
+
+       tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
+       put_stack_long(child, EFL_OFFSET, tmp);
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -320,26 +333,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
        }
 
-       case PTRACE_DETACH: { /* detach a process that was attached. */
-               long tmp;
-
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               child->ptrace = 0;
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               /* make sure the single step bit is not set. */
-               tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
-               put_stack_long(child, EFL_OFFSET, tmp);
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_DETACH:
+               /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
                break;
-       }
 
        case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
index 5a24d252a571126f14595496cf94952e2cbca859..a24b40386f92b6d29af51108cc484df0807f5e48 100644 (file)
@@ -943,7 +943,7 @@ void __init setup_arch(char **cmdline_p)
        reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
 #endif
 
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
        /*
         * Find and reserve possible boot-time SMP configuration:
         */
@@ -976,17 +976,16 @@ void __init setup_arch(char **cmdline_p)
        smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
 #endif
        paging_init();
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
        /*
         * get boot-time SMP configuration:
         */
        if (smp_found_config)
                get_smp_config();
-#endif
-#ifdef CONFIG_X86_LOCAL_APIC
        init_apic_mappings();
 #endif
 
+
        /*
         * Request address space for all standard RAM and ROM resources
         * and also for regions reported as reserved by the e820.
index a738a3a415e5d95da537543f28a7d41486f126c6..53bc8f1bfd20e11bc50acd0cf286cb466cda4e53 100644 (file)
@@ -429,9 +429,10 @@ struct call_data_struct {
        atomic_t started;
        atomic_t finished;
        int wait;
-};
+} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
 
 static struct call_data_struct * call_data;
+static struct call_data_struct call_data_array[NR_CPUS];
 
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
@@ -453,33 +454,45 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
  * hardware interrupt handler, you may call it from a bottom half handler.
  */
 {
-       struct call_data_struct data;
-       int cpus = smp_num_cpus-1;
+       struct call_data_struct *data;
+       int cpus = (cpu_online_map & ~(1 << smp_processor_id()));
 
        if (!cpus)
                return 0;
 
-       data.func = func;
-       data.info = info;
-       atomic_set(&data.started, 0);
-       data.wait = wait;
+       data = &call_data_array[smp_processor_id()];
+       
+       data->func = func;
+       data->info = info;
+       data->wait = wait;
        if (wait)
-               atomic_set(&data.finished, 0);
-
-       spin_lock_bh(&call_lock);
-       call_data = &data;
-       wmb();
+               atomic_set(&data->finished, 0);
+       /* We have do to this one last to make sure that the IPI service
+        * code desn't get confused if it gets an unexpected repeat
+        * trigger of an old IPI while we're still setting up the new
+        * one. */
+       atomic_set(&data->started, 0);
+
+       local_bh_disable();
+       spin_lock(&call_lock);
+       call_data = data;
        /* Send a message to all other CPUs and wait for them to respond */
        send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
        /* Wait for response */
-       while (atomic_read(&data.started) != cpus)
+       while (atomic_read(&data->started) != cpus)
                barrier();
 
+       /* It is now safe to reuse the "call_data" global, but we need
+        * to keep local bottom-halves disabled until after waiters have
+        * been acknowledged to prevent reuse of the per-cpu call data
+        * entry. */
+       spin_unlock(&call_lock);
+
        if (wait)
-               while (atomic_read(&data.finished) != cpus)
+               while (atomic_read(&data->finished) != cpus)
                        barrier();
-       spin_unlock_bh(&call_lock);
+       local_bh_enable();
 
        return 0;
 }
@@ -529,18 +542,17 @@ asmlinkage void smp_call_function_interrupt(void)
 
        ack_APIC_irq();
        /*
-        * Notify initiating CPU that I've grabbed the data and am
-        * about to execute the function
+        * Notify initiating CPU that I've grabbed the data and am about
+        * to execute the function (and avoid servicing any single IPI
+        * twice)
         */
-       mb();
-       atomic_inc(&call_data->started);
+       if (test_and_set_bit(smp_processor_id(), &call_data->started))
+               return;
        /*
         * At this point the info structure may be out of scope unless wait==1
         */
        (*func)(info);
-       if (wait) {
-               mb();
-               atomic_inc(&call_data->finished);
-       }
+       if (wait)
+               set_bit(smp_processor_id(), &call_data->finished);
 }
 
index 9d235f0caa32d8242911b67b7115f82c9b4d0127..c68867e6876e17a1044f1e8a74ff3f8b01b4cdc9 100644 (file)
@@ -780,7 +780,6 @@ static void __init do_boot_cpu (int apicid)
 }
 
 cycles_t cacheflush_time;
-extern unsigned long cpu_khz;
 
 static void smp_tune_scheduling (void)
 {
@@ -870,12 +869,15 @@ void __init smp_boot_cpus(void)
         * get out of here now!
         */
        if (!smp_found_config) {
-               printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
+               printk(KERN_NOTICE "SMP motherboard not detected.\n");
 #ifndef CONFIG_VISWS
                io_apic_irqs = 0;
 #endif
                cpu_online_map = phys_cpu_present_map = 1;
                smp_num_cpus = 1;
+               if (APIC_init_uniprocessor())
+                       printk(KERN_NOTICE "Local APIC not detected."
+                                          " Using dummy APIC emulation.\n");
                goto smp_done;
        }
 
@@ -1003,7 +1005,7 @@ void __init smp_boot_cpus(void)
         * Here we can be sure that there is an IO-APIC in the system. Let's
         * go and set it up:
         */
-       if (!skip_ioapic_setup)
+       if (!skip_ioapic_setup && nr_ioapics)
                setup_IO_APIC();
 #endif
 
@@ -1021,4 +1023,3 @@ void __init smp_boot_cpus(void)
 smp_done:
        zap_low_mappings();
 }
-
index 86bb215505227df4c49226cb03b34b79847ac02b..a66a15e4774421db5d1ceebea1b61f2d92800c3d 100644 (file)
@@ -422,7 +422,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
        if (!user_mode(regs))
                x86_do_profile(regs->eip);
 #else
-       if (!smp_found_config)
+       if (!using_apic_timer)
                smp_local_timer_interrupt(regs);
 #endif
 
index 58b8d59d4c61b2d29c1ae7a9afd2d37313d8057e..03181864d6516106a5006ec6ec576e6c2d9f596a 100644 (file)
@@ -186,7 +186,7 @@ void show_stack(unsigned long * esp)
        show_trace(esp);
 }
 
-static void show_registers(struct pt_regs *regs)
+void show_registers(struct pt_regs *regs)
 {
        int i;
        int in_kernel = 1;
@@ -418,108 +418,14 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
        printk("Do you have a strange power saving mode enabled?\n");
 }
 
-#if CONFIG_X86_IO_APIC
-
-int nmi_watchdog = 0;
-
-static int __init setup_nmi_watchdog(char *str)
-{
-        get_option(&str, &nmi_watchdog);
-        return 1;
-}
-
-__setup("nmi_watchdog=", setup_nmi_watchdog);
-
-static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
-
-static unsigned int
-       last_irq_sums [NR_CPUS],
-       alert_counter [NR_CPUS];
-
-/*
- * Sometimes, we know that we're disabling interrupts for too long.
- * This happens during long writes to slow console devices, and may
- * happen in other places.
- *
- * To prevent the NMI watchdog from firing when we're doing these things,
- * touch_nmi_watchdog() may be used to reset the NMI watchdog timer
- * back to its full interval (five seconds).
- */
-void touch_nmi_watchdog (void)
-{
-       int i;
-
-       /*
-        * Just reset the alert counters, (other CPUs might be
-        * spinning on locks we hold):
-        */
-       for (i = 0; i < smp_num_cpus; i++)
-               alert_counter[i] = 0;
-}
-
-/*
- * The best way to detect whether a CPU has a 'hard lockup' problem
- * is to check it's local APIC timer IRQ counts. If they are not
- * changing then that CPU has some problem.
- *
- * As these watchdog NMI IRQs are generated on every CPU, we only
- * have to check the current processor.
- *
- * Since NMIs don't listen to _any_ locks, we have to be extremely
- * careful not to rely on unsafe variables. The printk path might lock
- * up though, so we use bust_spinlocks() to break up any console
- * locks first.  There may be other tty-related locks which require
- * breaking as well.  They can be broken in bust_spinlocks(), or the
- * global variable `oops_in_progress' may be used to bypass the
- * tty locking.
- */
-
-inline void nmi_watchdog_tick(struct pt_regs * regs)
-{
-       /*
-        * Since current-> is always on the stack, and we always switch
-        * the stack NMI-atomically, it's safe to use smp_processor_id().
-        */
-       int sum, cpu = smp_processor_id();
-
-       sum = apic_timer_irqs[cpu];
-
-       if (last_irq_sums[cpu] == sum) {
-               /*
-                * Ayiee, looks like this CPU is stuck ...
-                * wait a few IRQs (5 seconds) before doing the oops ...
-                */
-               alert_counter[cpu]++;
-               if (alert_counter[cpu] == 5*HZ) {
-                       spin_lock(&nmi_print_lock);
-                       /*
-                        * We are in trouble anyway, lets at least try
-                        * to get a message out.
-                        */
-                       bust_spinlocks(1);
-                       printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
-                       show_registers(regs);
-                       printk("console shuts up ...\n");
-                       console_silent();
-                       spin_unlock(&nmi_print_lock);
-                       bust_spinlocks(0);
-                       do_exit(SIGSEGV);
-               }
-       } else {
-               last_irq_sums[cpu] = sum;
-               alert_counter[cpu] = 0;
-       }
-}
-#endif
-
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
        unsigned char reason = inb(0x61);
 
-
        ++nmi_count(smp_processor_id());
+
        if (!(reason & 0xc0)) {
-#if CONFIG_X86_IO_APIC
+#if CONFIG_X86_LOCAL_APIC
                /*
                 * Ok, so this is none of the documented NMI sources,
                 * so it must be the NMI watchdog.
@@ -527,11 +433,9 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
                if (nmi_watchdog) {
                        nmi_watchdog_tick(regs);
                        return;
-               } else
-                       unknown_nmi_error(reason, regs);
-#else
-               unknown_nmi_error(reason, regs);
+               }
 #endif
+               unknown_nmi_error(reason, regs);
                return;
        }
        if (reason & 0x80)
index f53734fe32cd9d5caa53eb7e12dc82115d0a8699..3bb1dc94cadb322fd6fca1ec2299be41f6bc4ff6 100644 (file)
@@ -44,6 +44,7 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
 unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
 {
+       prefetch(from);
        if (access_ok(VERIFY_WRITE, to, n))
                __copy_user(to,from,n);
        return n;
@@ -52,6 +53,7 @@ __generic_copy_to_user(void *to, const void *from, unsigned long n)
 unsigned long
 __generic_copy_from_user(void *to, const void *from, unsigned long n)
 {
+       prefetchw(to);
        if (access_ok(VERIFY_READ, from, n))
                __copy_user_zeroing(to,from,n);
        else
index c58d8b38419d76be39bc2969f42e836afb0a62ca..980ff9871a56a3ceb7afdda5c0c867f49d7ed01d 100644 (file)
@@ -111,7 +111,9 @@ void bust_spinlocks(int yes)
 #endif
        } else {
                int loglevel_save = console_loglevel;
+#ifdef CONFIG_VT
                unblank_screen();
+#endif
                oops_in_progress = 0;
                /*
                 * OK, the message is on the console.  Now we call printk()
@@ -124,16 +126,11 @@ void bust_spinlocks(int yes)
        }
 }
 
-#if 0
-/*
- * Verbose bug reporting: call do_BUG(__FILE__, __LINE__) in page.h:BUG() to enable this
- */
 void do_BUG(const char *file, int line)
 {
        bust_spinlocks(1);
        printk("kernel BUG at %s:%d!\n", file, line);
 }
-#endif
 
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 extern unsigned long idt;
index e13f8bf4235b9313f5fd46f2b7b974f615e7fe50..56b07ecb1de4189432f790ecf685970666512ce4 100644 (file)
@@ -789,6 +789,21 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
        return 0;
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* make sure the single step/take-branch tra bits are not set: */
+       ia64_psr(pt)->ss = 0;
+       ia64_psr(pt)->tb = 0;
+
+       /* Turn off flag indicating that the KRBS is sync'd with child's VM: */
+       child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
+}
+
 asmlinkage long
 sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
            long arg4, long arg5, long arg6, long arg7, long stack)
@@ -965,27 +980,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
                goto out_tsk;
 
              case PTRACE_DETACH:               /* detach a process that was attached. */
-               ret = -EIO;
-               if (data > _NSIG)
-                       goto out_tsk;
-
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               child->exit_code = data;
-               write_lock_irqsave(&tasklist_lock, flags);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irqrestore(&tasklist_lock, flags);
-
-               /* make sure the single step/take-branch tra bits are not set: */
-               ia64_psr(pt)->ss = 0;
-               ia64_psr(pt)->tb = 0;
-
-               /* Turn off flag indicating that the KRBS is sync'd with child's VM: */
-               child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED;
-
-               wake_up_process(child);
-               ret = 0;
+               ret = ptrace_detach(child, data);
                goto out_tsk;
 
              default:
index c29c9b286f7446a135f25291dbfee4d224782f8c..2de7e4d172dc6bef3bf40bd4a2ccd8385a2b3add 100644 (file)
@@ -87,6 +87,19 @@ static inline int put_reg(struct task_struct *task, int regno,
        return 0;
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       unsigned long tmp;
+       /* make sure the single step bit is not set. */
+       tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+       put_reg(child, PT_SR, tmp);
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -279,26 +292,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        break;
                }
 
-               case PTRACE_DETACH: { /* detach a process that was attached. */
-                       long tmp;
-
-                       ret = -EIO;
-                       if ((unsigned long) data > _NSIG)
-                               break;
-                       child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-                       child->exit_code = data;
-                       write_lock_irqsave(&tasklist_lock, flags);
-                       REMOVE_LINKS(child);
-                       child->p_pptr = child->p_opptr;
-                       SET_LINKS(child);
-                       write_unlock_irqrestore(&tasklist_lock, flags);
-                       /* make sure the single step bit is not set. */
-                       tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
-                       put_reg(child, PT_SR, tmp);
-                       wake_up_process(child);
-                       ret = 0;
+               case PTRACE_DETACH:     /* detach a process that was attached. */
+                       ret = ptrace_detach(child, data);
                        break;
-               }
 
                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
                        int i;
index e52fd516cb8eb292dbcf8cbcccd0ccfcc7107814..7f9f3aacf42d1224192af341bf74200f94f2ae49 100644 (file)
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* Nothing to do.. */
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -291,18 +301,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
 
        case PTRACE_DETACH: /* detach a process that was attached. */
-               res = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               child->ptrace = 0;
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               wake_up_process(child);
-               res = 0;
+               res = ptrace_detach(child, data);
                break;
 
        case PTRACE_SETOPTIONS:
index 43510218563ee7a1332f84a053c68a28c15ca675..c90b1428e8c243b85802417577713e39f82e7b77 100644 (file)
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* Nothing to do.. */
+}
+
 /*
  * Tracing a 32-bit process with a 64-bit strace and vice versa will not
  * work.  I don't know how to fix this.
@@ -261,21 +271,9 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
                break;
        }
 
-       case PTRACE_DETACH: { /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               child->ptrace = 0;
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_DETACH: /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
                break;
-       }
 
        case PTRACE_SETOPTIONS: {
                if (data & PTRACE_O_TRACESYSGOOD)
@@ -533,21 +531,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
        }
 
-       case PTRACE_DETACH: { /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               child->ptrace = 0;
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_DETACH: /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
                break;
-       }
 
        case PTRACE_SETOPTIONS: {
                if (data & PTRACE_O_TRACESYSGOOD)
index 770df51822dc796cc46d43ac9fc82195955a3a5b..d44e0238d8ac4071db8920d70cd49644464db8ed 100644 (file)
 #define PT_SINGLESTEP  0x10000
 #define PT_BLOCKSTEP   0x20000
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* make sure the trap bits are not set */
+       pa_psw(child)->r = 0;
+       pa_psw(child)->t = 0;
+       pa_psw(child)->h = 0;
+       pa_psw(child)->l = 0;
+}
+
 long sys_ptrace(long request, pid_t pid, long addr, long data)
 {
        struct task_struct *child;
@@ -226,17 +240,8 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
                goto out_wake;
 
        case PTRACE_DETACH:
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       goto out_tsk;
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS|PT_SINGLESTEP|PT_BLOCKSTEP);
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               goto out_wake_notrap;
+               ret = ptrace_detach(child, data);
+               goto out_tsk;
 
        default:
                ret = -EIO;
index caea126dc198388783f7da53d879faae34128336..993068c91ce225b635914d8bb57ea3c1b44d3b4c 100644 (file)
@@ -89,6 +89,17 @@ clear_single_step(struct task_struct *task)
                regs->msr &= ~MSR_SE;
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* make sure the single step bit is not set. */
+       clear_single_step(child);
+}
+
 int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -249,23 +260,9 @@ int sys_ptrace(long request, long pid, long addr, long data)
                break;
        }
 
-       case PTRACE_DETACH: { /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               /* make sure the single step bit is not set. */
-               clear_single_step(child);
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_DETACH:
+               ret = ptrace_detach(child, data);
                break;
-       }
 
        default:
                ret = -EIO;
index b166d15272b8dde8ccc0f7818d71649033493bde..ba63fb004b613bba2a45967a84ae013c6c896da8 100644 (file)
@@ -202,6 +202,17 @@ int copy_user(struct task_struct *task,saddr_t useraddr,addr_t copyaddr,int len,
        return(0);
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* make sure the single step bit is not set. */
+       clear_single_step(child);
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -327,20 +338,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
 
        case PTRACE_DETACH:  /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data >= _NSIG)
-                       break;
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               child->exit_code = data;
-               write_lock_irqsave(&tasklist_lock, flags);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irqrestore(&tasklist_lock, flags);
-               /* make sure the single step bit is not set. */
-               clear_single_step(child);
-               wake_up_process(child);
-               ret = 0;
+               ret = ptrace_detach(child, data);
                break;
        case PTRACE_PEEKUSR_AREA:
        case PTRACE_POKEUSR_AREA:
index 0ade6ea3fbb215651c744fce8fdda565c1dc9b90..58fa682e68b8f404a1c66842d94cd24649710894 100644 (file)
@@ -216,6 +216,17 @@ int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
        return(0);
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* make sure the single step bit is not set. */
+       clear_single_step(child);
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -341,21 +352,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
 
        case PTRACE_DETACH:  /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data >= _NSIG)
-                       break;
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               child->exit_code = data;
-               write_lock_irqsave(&tasklist_lock, flags);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irqrestore(&tasklist_lock, flags);
-               /* make sure the single step bit is not set. */
-               clear_single_step(child);
-               wake_up_process(child);
-               ret = 0;
+               ret = ptrace_detach(child, data);
                break;
+
        case PTRACE_PEEKUSR_AREA:
        case PTRACE_POKEUSR_AREA:
                if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
index 3c256d1677038fb7c9cf33a1a05d169e67f221b2..66ade5564eab1ea25e65f7570142875429aed088 100644 (file)
@@ -147,6 +147,16 @@ ubc_set_tracing(int asid, unsigned long nextpc1, unsigned nextpc2)
                ctrl_outw(BRCR_PCBA | BRCR_PCBB, UBC_BRCR);
 }
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* nothing to do.. */
+}
+
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child, *tsk = current;
@@ -342,21 +352,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
        }
 
-       case PTRACE_DETACH: { /* detach a process that was attached. */
-               ret = -EIO;
-               if ((unsigned long) data > _NSIG)
-                       break;
-               child->ptrace = 0;
-               child->exit_code = data;
-               write_lock_irq(&tasklist_lock);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irq(&tasklist_lock);
-               wake_up_process(child);
-               ret = 0;
+       case PTRACE_DETACH: /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
                break;
-       }
 
        case PTRACE_SETOPTIONS: {
                if (data & PTRACE_O_TRACESYSGOOD)
index c33b785afb088f2ae9e64d409a70defcfbb4a6ac..8b85b4f9d6ece2efdf0bca4435644e00ddb3d3d3 100644 (file)
@@ -260,6 +260,16 @@ char *pt_rq [] = {
 };
 #endif
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* nothing to do */
+}
+
 asmlinkage void do_ptrace(struct pt_regs *regs)
 {
        unsigned long request = regs->u_regs[UREG_I0];
@@ -576,19 +586,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
        }
 
        case PTRACE_SUNDETACH: { /* detach a process that was attached. */
-               unsigned long flags;
-               if ((unsigned long) data > _NSIG) {
+               int err = ptrace_detach(child, data);
+               if (err) {
                        pt_error_return(regs, EIO);
                        goto out_tsk;
                }
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               wake_up_process(child);
-               child->exit_code = data;
-               write_lock_irqsave(&tasklist_lock, flags);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irqrestore(&tasklist_lock, flags);
                pt_succ_return(regs, 0);
                goto out_tsk;
        }
index ea6e6b713e0fcc329683ffef5244cac139777caa..3b5d37ed1f757b47383b881d29538bed00a62ce6 100644 (file)
@@ -105,6 +105,16 @@ char *pt_rq [] = {
 };
 #endif
 
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* nothing to do */
+}
+
 asmlinkage void do_ptrace(struct pt_regs *regs)
 {
        int request = regs->u_regs[UREG_I0];
@@ -562,22 +572,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
        }
 
        case PTRACE_SUNDETACH: { /* detach a process that was attached. */
-               unsigned long flags;
-
-               if ((unsigned long) data > _NSIG) {
+               int error = ptrace_detach(child, data);
+               if (error) {
                        pt_error_return(regs, EIO);
                        goto out_tsk;
                }
-               child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-               child->exit_code = data;
-
-               write_lock_irqsave(&tasklist_lock, flags);
-               REMOVE_LINKS(child);
-               child->p_pptr = child->p_opptr;
-               SET_LINKS(child);
-               write_unlock_irqrestore(&tasklist_lock, flags);
-
-               wake_up_process(child);
                pt_succ_return(regs, 0);
                goto out_tsk;
        }
index 1d834f76d4f3535facd93193a3db5e77997e1c6f..4bc4446e58bbda2c5d91e5f7dd344e2fc3b910b2 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
          iphase.c: Device driver for Interphase ATM PCI adapter cards 
                     Author: Peter Wang  <pwang@iphase.com>            
+                  Some fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                    Interphase Corporation  <www.iphase.com>           
                                Version: 1.0                           
 *******************************************************************************
@@ -79,7 +80,7 @@ static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr);
 
 static IADEV *ia_dev[8];
 static struct atm_dev *_ia_dev[8];
-static int iadev_count = 0;
+static int iadev_count;
 static void ia_led_timer(unsigned long arg);
 static struct timer_list ia_timer = { function: ia_led_timer };
 struct atm_vcc *vcc_close_que[100];
@@ -96,6 +97,8 @@ MODULE_PARM(IA_RX_BUF_SZ, "i");
 MODULE_PARM(IADebugFlag, "i");
 #endif
 
+MODULE_LICENSE("GPL");
+
 #if BITS_PER_LONG != 32
 #  error FIXME: this driver only works on 32-bit platforms
 #endif
@@ -121,8 +124,7 @@ static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data)
 }
 
 static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) {
-   IARTN_Q *entry;
-   entry = (IARTN_Q *)kmalloc(sizeof(IARTN_Q), GFP_KERNEL);
+   IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_KERNEL);
    if (!entry) return -1;
    entry->data = data;
    entry->next = NULL;
@@ -429,7 +431,7 @@ ia_open_abr_vc(IADEV *dev, srv_cls_param_t *srv_p,
        if (srv_p->rdf > MAX_RDF)
          return INVALID_RDF;
 #endif
-       memset ((caddr_t)f_abr_vc, 0, sizeof(f_vc_abr_entry));
+       memset ((caddr_t)f_abr_vc, 0, sizeof(*f_abr_vc));
        f_abr_vc->f_vc_type = ABR;
        nrm = 2 << srv_p->nrm;     /* (2 ** (srv_p->nrm +1)) */
                                  /* i.e 2**n = 2 << (n-1) */
@@ -544,7 +546,7 @@ static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) {
       TstSchedTbl = (u16*)(SchedTbl+testSlot);  //set index and read in value
       IF_CBR(printk("CBR Testslot 0x%x AT Location 0x%x, NumToAssign=%d\n",
                                 testSlot, (u32)TstSchedTbl,toBeAssigned);) 
-      memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16));
+      memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC));
       while (cbrVC)  // If another VC at this location, we have to keep looking
       {
           inc++;
@@ -555,7 +557,7 @@ static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) {
                                                        (u32)SchedTbl,testSlot);)
           }
           TstSchedTbl = (u16 *)(SchedTbl + testSlot);  // set table index
-          memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); 
+          memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); 
           if (!cbrVC)
              break;
           testSlot = idealSlot + inc;
@@ -569,10 +571,10 @@ static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) {
           TstSchedTbl = (u16*)(SchedTbl + testSlot);
           IF_CBR(printk("Reading CBR Tbl from 0x%x, CbrVal=0x%x Iteration %d\n",
                           (u32)TstSchedTbl,cbrVC,inc);) 
-          memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16));
+          memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC));
        } /* while */
        // Move this VCI number into this location of the CBR Sched table.
-       memcpy((caddr_t)TstSchedTbl, (caddr_t)&vcIndex,sizeof(u16));
+       memcpy((caddr_t)TstSchedTbl, (caddr_t)&vcIndex,sizeof(TstSchedTbl));
        dev->CbrRemEntries--;
        toBeAssigned--;
    } /* while */ 
@@ -658,20 +660,20 @@ void ia_tx_poll (IADEV *iadev) {
        skb = rtne->data.txskb;
        if (!skb) {
            printk("ia_tx_poll: skb is null\n");
-           return;
+           goto out;
        }
        vcc = ATM_SKB(skb)->vcc;
        if (!vcc) {
            printk("ia_tx_poll: vcc is null\n");
            dev_kfree_skb_any(skb);
-           return;
+          goto out;
        }
 
        iavcc = INPH_IA_VCC(vcc);
        if (!iavcc) {
            printk("ia_tx_poll: iavcc is null\n");
            dev_kfree_skb_any(skb);
-           return;
+          goto out;
        }
 
        skb1 = skb_dequeue(&iavcc->txing_skb);
@@ -680,7 +682,7 @@ void ia_tx_poll (IADEV *iadev) {
              printk("IA_tx_intr: Vci %d lost pkt!!!\n", vcc->vci);
           }
           IF_ERR(printk("Release the SKB not match\n");)
-          if (vcc && (vcc->pop) && (skb1->len != 0))
+          if ((vcc->pop) && (skb1->len != 0))
           {
              vcc->pop(vcc, skb1);
              IF_EVENT(printk("Tansmit Done - skb 0x%lx return\n",
@@ -695,7 +697,7 @@ void ia_tx_poll (IADEV *iadev) {
           ia_enque_head_rtn_q (&iadev->tx_return_q, rtne);
           break;
        }
-       if (vcc && (vcc->pop) && (skb->len != 0))
+       if ((vcc->pop) && (skb->len != 0))
        {
           vcc->pop(vcc, skb);
           IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);)
@@ -705,6 +707,7 @@ void ia_tx_poll (IADEV *iadev) {
        kfree(rtne);
     }
     ia_que_tx(iadev);
+out:
     return;
 }
 #if 0
@@ -924,9 +927,9 @@ void ia_suni_pm7345_init (IADEV *iadev)
    suni_pm7345->suni_rxcp_ctrl = 0x2c;
    suni_pm7345->suni_rxcp_fctrl = 0x81;
  
-   suni_pm7345->suni_rxcp_idle_pat_h1 = 0;
-   suni_pm7345->suni_rxcp_idle_pat_h2 = 0;
-   suni_pm7345->suni_rxcp_idle_pat_h3 = 0;
+   suni_pm7345->suni_rxcp_idle_pat_h1 =
+       suni_pm7345->suni_rxcp_idle_pat_h2 =
+       suni_pm7345->suni_rxcp_idle_pat_h3 = 0;
    suni_pm7345->suni_rxcp_idle_pat_h4 = 1;
  
    suni_pm7345->suni_rxcp_idle_mask_h1 = 0xff;
@@ -934,15 +937,15 @@ void ia_suni_pm7345_init (IADEV *iadev)
    suni_pm7345->suni_rxcp_idle_mask_h3 = 0xff;
    suni_pm7345->suni_rxcp_idle_mask_h4 = 0xfe;
  
-   suni_pm7345->suni_rxcp_cell_pat_h1 = 0;
-   suni_pm7345->suni_rxcp_cell_pat_h2 = 0;
-   suni_pm7345->suni_rxcp_cell_pat_h3 = 0;
+   suni_pm7345->suni_rxcp_cell_pat_h1 =
+       suni_pm7345->suni_rxcp_cell_pat_h2 =
+       suni_pm7345->suni_rxcp_cell_pat_h3 = 0;
    suni_pm7345->suni_rxcp_cell_pat_h4 = 1;
  
-   suni_pm7345->suni_rxcp_cell_mask_h1 = 0xff;
-   suni_pm7345->suni_rxcp_cell_mask_h2 = 0xff;
-   suni_pm7345->suni_rxcp_cell_mask_h3 = 0xff;
-   suni_pm7345->suni_rxcp_cell_mask_h4 = 0xff;
+   suni_pm7345->suni_rxcp_cell_mask_h1 =
+       suni_pm7345->suni_rxcp_cell_mask_h2 =
+       suni_pm7345->suni_rxcp_cell_mask_h3 =
+       suni_pm7345->suni_rxcp_cell_mask_h4 = 0xff;
  
    suni_pm7345->suni_txcp_ctrl = 0xa4;
    suni_pm7345->suni_txcp_intr_en_sts = 0x10;
@@ -1144,8 +1147,7 @@ static int rx_pkt(struct atm_dev *dev)
                 else {
                     IF_ERR(printk(" cause: buffer over flow\n");)
                 }
-               free_desc(dev, desc);  
-               return 0;  
+               goto out_free_desc;
        }  
   
        /*  
@@ -1158,8 +1160,7 @@ static int rx_pkt(struct atm_dev *dev)
         if (len > iadev->rx_buf_sz) {
            printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz);
            atomic_inc(&vcc->stats->rx_err);
-           free_desc(dev, desc); 
-           return 0;
+          goto out_free_desc;
         }
                  
 #if LINUX_VERSION_CODE >= 0x20312
@@ -1173,8 +1174,7 @@ static int rx_pkt(struct atm_dev *dev)
               IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");)  
               atomic_inc(&vcc->stats->rx_drop);
               atm_return(vcc, atm_pdu2truesize(len));
-              free_desc(dev, desc); 
-             return 0;  
+             goto out_free_desc;
           }  
         }
         else {
@@ -1182,8 +1182,7 @@ static int rx_pkt(struct atm_dev *dev)
 #endif
            if (vcc->vci < 32)
               printk("Drop control packets\n");
-           free_desc(dev, desc);
-           return 0;
+             goto out_free_desc;
         }
        skb_put(skb,len);  
         // pwang_test
@@ -1206,7 +1205,10 @@ static int rx_pkt(struct atm_dev *dev)
        udelay(1);  
        /* Increment transaction counter */  
        writel(1, iadev->dma+IPHASE5575_RX_COUNTER);   
-       return 0;  
+out:   return 0;  
+out_free_desc:
+        free_desc(dev, desc);
+        goto out;
 }  
   
 static void rx_intr(struct atm_dev *dev)  
@@ -1280,6 +1282,7 @@ static void rx_dle_intr(struct atm_dev *dev)
   u_short state;   
   struct dle *dle, *cur_dle;  
   u_int dle_lp;  
+  int len;
   iadev = INPH_IA_DEV(dev);  
  
   /* free all the dles done, that is just update our own dle read pointer   
@@ -1299,7 +1302,7 @@ static void rx_dle_intr(struct atm_dev *dev)
       desc = ATM_DESC(skb);
       free_desc(dev, desc);  
                
-      if (!skb->len)  
+      if (!(len = skb->len))
       {  
           printk("rx_dle_intr: skb len 0\n");  
          dev_kfree_skb_any(skb);  
@@ -1313,7 +1316,6 @@ static void rx_dle_intr(struct atm_dev *dev)
           vcc = ATM_SKB(skb)->vcc;
          if (!vcc) {
              printk("IA: null vcc\n");  
-              atomic_inc(&vcc->stats->rx_err);
               dev_kfree_skb_any(skb);
               goto INCR_DLE;
           }
@@ -1323,27 +1325,27 @@ static void rx_dle_intr(struct atm_dev *dev)
              atomic_inc(&vcc->stats->rx_err);
              dev_kfree_skb_any(skb);
 #if LINUX_VERSION_CODE >= 0x20312
-             atm_return(vcc, atm_guess_pdu2truesize(skb->len));
+             atm_return(vcc, atm_guess_pdu2truesize(len));
 #else
-             atm_return(vcc, atm_pdu2truesize(skb->len));
+             atm_return(vcc, atm_pdu2truesize(len));
 #endif
              goto INCR_DLE;
            }
           // get real pkt length  pwang_test
           trailer = (struct cpcs_trailer*)((u_char *)skb->data +
-                                 skb->len - sizeof(struct cpcs_trailer));
+                                 skb->len - sizeof(*trailer));
           length =  swap(trailer->length);
           if ((length > iadev->rx_buf_sz) || (length > 
                               (skb->len - sizeof(struct cpcs_trailer))))
           {
              atomic_inc(&vcc->stats->rx_err);
-             dev_kfree_skb_any(skb);
              IF_ERR(printk("rx_dle_intr: Bad  AAL5 trailer %d (skb len %d)", 
                                                             length, skb->len);)
+             dev_kfree_skb_any(skb);
 #if LINUX_VERSION_CODE >= 0x20312
-             atm_return(vcc, atm_guess_pdu2truesize(skb->len));
+             atm_return(vcc, atm_guess_pdu2truesize(len));
 #else
-             atm_return(vcc, atm_pdu2truesize(skb->len));
+             atm_return(vcc, atm_pdu2truesize(len));
 #endif 
              goto INCR_DLE;
           }
@@ -1429,7 +1431,7 @@ static int rx_init(struct atm_dev *dev)
        IADEV *iadev;  
        struct rx_buf_desc *buf_desc_ptr;  
        unsigned long rx_pkt_start = 0;  
-       u32 *dle_addr;  
+       u32 *odle_addr, *dle_addr;  
        struct abr_vc_table  *abr_vc_table; 
        u16 *vc_table;  
        u16 *reass_table;  
@@ -1451,13 +1453,14 @@ static int rx_init(struct atm_dev *dev)
        */   
   
        /* allocate 8k bytes */  
-       dle_addr = (u32*)kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
-       if (!dle_addr)  
+       odle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
+       if (!odle_addr)  
        {  
                printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");  
+               return -ENOMEM;
        }  
        /* find 4k byte boundary within the 8k allocated */  
-       dle_addr = (u32*)( ((u32)dle_addr+(4096-1)) & ~(4096-1) );  
+       dle_addr = (u32*)( ((u32)odle_addr+(4096-1)) & ~(4096-1) );  
        iadev->rx_dle_q.start = (struct dle*)dle_addr;  
        iadev->rx_dle_q.read = iadev->rx_dle_q.start;  
        iadev->rx_dle_q.write = iadev->rx_dle_q.start;  
@@ -1499,12 +1502,12 @@ static int rx_init(struct atm_dev *dev)
        /* Initialize each entry in the Buffer Descriptor Table */  
         iadev->RX_DESC_BASE_ADDR = iadev->reass_ram+RX_DESC_BASE*iadev->memSize;
        buf_desc_ptr =(struct rx_buf_desc *)iadev->RX_DESC_BASE_ADDR;
-       memset((caddr_t)buf_desc_ptr, 0, sizeof(struct rx_buf_desc));  
+       memset((caddr_t)buf_desc_ptr, 0, sizeof(*buf_desc_ptr));  
        buf_desc_ptr++;  
        rx_pkt_start = iadev->rx_pkt_ram;  
        for(i=1; i<=iadev->num_rx_desc; i++)  
        {  
-               memset((caddr_t)buf_desc_ptr, 0, sizeof(struct rx_buf_desc));  
+               memset((caddr_t)buf_desc_ptr, 0, sizeof(*buf_desc_ptr));  
                buf_desc_ptr->buf_start_hi = rx_pkt_start >> 16;  
                buf_desc_ptr->buf_start_lo = rx_pkt_start & 0x0000ffff;  
                buf_desc_ptr++;           
@@ -1599,7 +1602,7 @@ static int rx_init(struct atm_dev *dev)
         i = ABR_VC_TABLE * iadev->memSize;
        abr_vc_table = (struct abr_vc_table *)(iadev->reass_ram+i);  
         j = REASS_TABLE_SZ * iadev->memSize;
-        memset ((char*)abr_vc_table, 0, j * sizeof(struct abr_vc_table ) );
+        memset ((char*)abr_vc_table, 0, j * sizeof(*abr_vc_table));
        for(i = 0; i < j; i++) {                
                abr_vc_table->rdf = 0x0003;
                abr_vc_table->air = 0x5eb1;
@@ -1635,11 +1638,12 @@ static int rx_init(struct atm_dev *dev)
   
        skb_queue_head_init(&iadev->rx_dma_q);  
        iadev->rx_free_desc_qhead = NULL;   
-       iadev->rx_open =(struct atm_vcc **)kmalloc(4*iadev->num_vc,GFP_KERNEL);
+       iadev->rx_open = kmalloc(4*iadev->num_vc,GFP_KERNEL);
        if (!iadev->rx_open)  
        {  
                printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n",
                dev->number);  
+               kfree(odle_addr);
                return -ENOMEM;  
        }  
        memset(iadev->rx_open, 0, 4*iadev->num_vc);  
@@ -1770,7 +1774,7 @@ static int open_tx(struct atm_vcc *vcc)
           }
         }
         ia_vcc =  INPH_IA_VCC(vcc);
-        memset((caddr_t)ia_vcc, 0, sizeof(struct ia_vcc));
+        memset((caddr_t)ia_vcc, 0, sizeof(*ia_vcc));
         if (vcc->qos.txtp.max_sdu > 
                          (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){
            printk("IA:  SDU size over the configured SDU size %d\n",
@@ -1815,8 +1819,8 @@ static int open_tx(struct atm_vcc *vcc)
        evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR;  
        vc += vcc->vci;  
        evc += vcc->vci;  
-       memset((caddr_t)vc, 0, sizeof(struct main_vc));  
-       memset((caddr_t)evc, 0, sizeof(struct ext_vc));  
+       memset((caddr_t)vc, 0, sizeof(*vc));  
+       memset((caddr_t)evc, 0, sizeof(*evc));  
          
        /* store the most significant 4 bits of vci as the last 4 bits   
                of first part of atm header.  
@@ -1921,10 +1925,11 @@ static int tx_init(struct atm_dev *dev)
                                 readw(iadev->seg_reg+SEG_MASK_REG));)  
        /*---------- Initializing Transmit DLEs ----------*/  
        /* allocating 8k memory for transmit DLEs */  
-       dle_addr = (u32*)kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
+       dle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
        if (!dle_addr)  
        {  
                printk(KERN_ERR DEV_LABEL "can't allocate TX DLEs\n");  
+               return -ENOMEM;
        }  
   
        /* find 4k byte boundary within the 8k allocated */  
@@ -1967,20 +1972,19 @@ static int tx_init(struct atm_dev *dev)
   
        /* initialize each entry in the buffer descriptor table */  
        buf_desc_ptr =(struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE);  
-       memset((caddr_t)buf_desc_ptr, 0, sizeof(struct tx_buf_desc));  
+       memset((caddr_t)buf_desc_ptr, 0, sizeof(*buf_desc_ptr));  
        buf_desc_ptr++;  
        tx_pkt_start = TX_PACKET_RAM;  
        for(i=1; i<=iadev->num_tx_desc; i++)  
        {  
-               memset((caddr_t)buf_desc_ptr, 0, sizeof(struct tx_buf_desc));  
+               memset((caddr_t)buf_desc_ptr, 0, sizeof(*buf_desc_ptr));  
                buf_desc_ptr->desc_mode = AAL5;  
                buf_desc_ptr->buf_start_hi = tx_pkt_start >> 16;  
                buf_desc_ptr->buf_start_lo = tx_pkt_start & 0x0000ffff;  
                buf_desc_ptr++;           
                tx_pkt_start += iadev->tx_buf_sz;  
        }  
-        iadev->tx_buf= (caddr_t*)kmalloc(iadev->num_tx_desc*sizeof(caddr_t), 
-                                                                   GFP_KERNEL);
+        iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(caddr_t), GFP_KERNEL);
         if (!iadev->tx_buf) {
             printk(KERN_ERR DEV_LABEL " couldn't get mem\n");
             return -EAGAIN;
@@ -1988,14 +1992,14 @@ static int tx_init(struct atm_dev *dev)
                for (i= 0; i< iadev->num_tx_desc; i++)
                {
  
-                   iadev->tx_buf[i] =(caddr_t)kmalloc(sizeof(struct cpcs_trailer),
+                   iadev->tx_buf[i] = kmalloc(sizeof(struct cpcs_trailer),
                                                            GFP_KERNEL|GFP_DMA);
             if(!iadev->tx_buf[i]) {                
                printk(KERN_ERR DEV_LABEL " couldn't get freepage\n"); 
                return -EAGAIN;
             }
         }
-        iadev->desc_tbl = (struct desc_tbl_t *)kmalloc(iadev->num_tx_desc *
+        iadev->desc_tbl = kmalloc(iadev->num_tx_desc *
                                    sizeof(struct desc_tbl_t), GFP_KERNEL);
   
        /* Communication Queues base address */  
@@ -2121,18 +2125,17 @@ static int tx_init(struct atm_dev *dev)
        memset((caddr_t)(iadev->seg_ram+i),  0, iadev->num_vc*4);
        vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR;  
        evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR;  
-        iadev->testTable = (struct testTable_t **)
-                          kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL); 
+        iadev->testTable = kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL); 
         if (!iadev->testTable) {
            printk("Get freepage  failed\n");
            return -EAGAIN; 
         }
        for(i=0; i<iadev->num_vc; i++)  
        {  
-               memset((caddr_t)vc, 0, sizeof(struct main_vc));  
-               memset((caddr_t)evc, 0, sizeof(struct ext_vc));  
-                iadev->testTable[i] = (struct testTable_t *)
-                            kmalloc(sizeof(struct testTable_t), GFP_KERNEL);
+               memset((caddr_t)vc, 0, sizeof(*vc));  
+               memset((caddr_t)evc, 0, sizeof(*evc));  
+                iadev->testTable[i] = kmalloc(sizeof(struct testTable_t),
+                                               GFP_KERNEL);
                if (!iadev->testTable[i])
                        return -ENOMEM;
                iadev->testTable[i]->lastTime = 0;
@@ -2682,7 +2685,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
                                  vcc->dev->number, vcc->vpi, vcc->vci);)  
   
        /* Device dependent initialization */  
-       ia_vcc = kmalloc(sizeof(struct ia_vcc), GFP_KERNEL);  
+       ia_vcc = kmalloc(sizeof(*ia_vcc), GFP_KERNEL);  
        if (!ia_vcc) return -ENOMEM;  
        INPH_IA_VCC(vcc) = ia_vcc;  
   
@@ -2989,7 +2992,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
 
        /* Build the DLE structure */  
        wr_ptr = iadev->tx_dle_q.write;  
-       memset((caddr_t)wr_ptr, 0, sizeof(struct dle));  
+       memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr));  
        wr_ptr->sys_pkt_addr = addr;  
        wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | 
                                                   buf_desc_ptr->buf_start_lo;  
@@ -3175,9 +3178,9 @@ __initfunc(int ia_detect(void))
                printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n");  
                return 0;  
        }  
-       iadev = (IADEV *)kmalloc(sizeof(IADEV), GFP_KERNEL); 
+       iadev = kmalloc(sizeof(*iadev), GFP_KERNEL); 
        if (!iadev) return -ENOMEM;  
-        memset((char*)iadev, 0, sizeof(IADEV));
+        memset((char*)iadev, 0, sizeof(*iadev));
        prev_dev = NULL;  
        while((iadev->pci = pci_find_device(PCI_VENDOR_ID_IPHASE,  
                PCI_DEVICE_ID_IPHASE_5575,  prev_dev))) {  
@@ -3212,10 +3215,9 @@ __initfunc(int ia_detect(void))
                prev_dev = iadev->pci;  
                iadev->next_board = ia_boards;  
                ia_boards = dev;  
-               iadev = (IADEV *)kmalloc(   
-                               sizeof(IADEV), GFP_KERNEL);  
+               iadev = kmalloc(sizeof(*iadev), GFP_KERNEL);  
                if (!iadev) break;   
-                memset((char*)iadev, 0, sizeof(IADEV)); 
+                memset((char*)iadev, 0, sizeof(*iadev)); 
                index++;  
                 dev = NULL;
        }  
index a7f191b04ad6816cf15d11c3737ad1a8b3fa422e..82513ff1dc9bd435eaeeb99c896b7de7bc3f05c5 100644 (file)
@@ -416,6 +416,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
        case BLKRASET:
        case BLKRAGET:
        case BLKPG:
+       case BLKELVGET:
+       case BLKELVSET:
                return( blk_ioctl(inode->i_rdev, cmd, arg));
        case CCISS_GETPCIINFO:
        {
index a9183fb1ce4e91bc6c6a28c5489d6d0469407fb9..30347c95681c8ec789f235c72a6bbc299de9e2d7 100644 (file)
@@ -1262,6 +1262,8 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
        case BLKROGET:
        case BLKRASET:
        case BLKRAGET:
+       case BLKELVGET:
+       case BLKELVSET:
        case BLKPG:
                return blk_ioctl(inode->i_rdev, cmd, arg);
 
index 0aa921d4e51ae6ffb43e95254b19abc9acb23d56..8732563748a391925d0452317d9079d3e179b525 100644 (file)
@@ -28,7 +28,7 @@ int verbose=0; /* set this to 1 to see debugging messages and whatnot */
 #define EXPORT_SYMTAB 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 #include <asm/io.h>
 
index 633a9c9df4b1f49b8362459d61cfe9c175260516..c7e4d9991be1e5a6d41cf6f71ce17e4857813644 100644 (file)
@@ -536,6 +536,8 @@ MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
 MODULE_PARM     (rd_blocksize, "i");
 MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes.");
 
+MODULE_LICENSE("GPL");
+
 /* End of non-loading portions of the RAM disk driver */
 
 #ifdef RD_LOADER 
index 23e50f5ff56c82205b0a33dded1201ed7685f760..c667fb759d23ac8167a206fb5f77786557dcfd72 100644 (file)
@@ -120,6 +120,9 @@ struct agp_bridge_data {
        void (*free_by_type) (agp_memory *);
        unsigned long (*agp_alloc_page) (void);
        void (*agp_destroy_page) (unsigned long);
+       int (*suspend)(void);
+       void (*resume)(void);
+       
 };
 
 #define OUTREG32(mmap, addr, val)   __raw_writel((val), (mmap)+(addr))
@@ -157,6 +160,9 @@ struct agp_bridge_data {
 #ifndef PCI_DEVICE_ID_VIA_8363_0
 #define PCI_DEVICE_ID_VIA_8363_0      0x0305
 #endif
+#ifndef PCI_DEVICE_ID_VIA_82C694X_0
+#define PCI_DEVICE_ID_VIA_82C694X_0      0x0605
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_810_0
 #define PCI_DEVICE_ID_INTEL_810_0       0x7120
 #endif
@@ -196,8 +202,8 @@ struct agp_bridge_data {
 #ifndef PCI_DEVICE_ID_AMD_IRONGATE_0
 #define PCI_DEVICE_ID_AMD_IRONGATE_0    0x7006
 #endif
-#ifndef PCI_DEVICE_ID_AMD_761_0
-#define PCI_DEVICE_ID_AMD_761_0         0x700e
+#ifndef PCI_DEVICE_ID_AMD_762_0
+#define PCI_DEVICE_ID_AMD_762_0                0x700C
 #endif
 #ifndef PCI_VENDOR_ID_AL
 #define PCI_VENDOR_ID_AL               0x10b9
index a5bc5f2904888b7702aa5a9be4fee93d685e7584..077a109478f04209708d79631dbeacd27cf91356 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/miscdevice.h>
+#include <linux/pm.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -48,6 +49,7 @@
 
 MODULE_AUTHOR("Jeff Hartmann <jhartmann@precisioninsight.com>");
 MODULE_PARM(agp_try_unsupported, "1i");
+MODULE_LICENSE("GPL and additional rights");
 EXPORT_SYMBOL(agp_free_memory);
 EXPORT_SYMBOL(agp_allocate_memory);
 EXPORT_SYMBOL(agp_copy_info);
@@ -636,6 +638,15 @@ static int agp_generic_create_gatt_table(void)
        return 0;
 }
 
+static int agp_generic_suspend(void)
+{
+       return 0;
+}
+
+static void agp_generic_resume(void)
+{
+}
+
 static int agp_generic_free_gatt_table(void)
 {
        int page_order;
@@ -784,28 +795,31 @@ static void agp_generic_free_by_type(agp_memory * curr)
 
 static unsigned long agp_generic_alloc_page(void)
 {
-       void *pt;
-
-       pt = (void *) __get_free_page(GFP_KERNEL);
-       if (pt == NULL) {
+       struct page * page;
+       
+       page = alloc_page(GFP_KERNEL);
+       if (page == NULL) {
                return 0;
        }
-       atomic_inc(&virt_to_page(pt)->count);
-       set_bit(PG_locked, &virt_to_page(pt)->flags);
+       atomic_inc(&page->count);
+       set_bit(PG_locked, &page->flags);
        atomic_inc(&agp_bridge.current_memory_agp);
-       return (unsigned long) pt;
+       return (unsigned long)page_address(page);
 }
 
-static void agp_generic_destroy_page(unsigned long page)
+static void agp_generic_destroy_page(unsigned long addr)
 {
-       void *pt = (void *) page;
+       void *pt = (void *) addr;
+       struct page *page;
 
        if (pt == NULL) {
                return;
        }
-       atomic_dec(&virt_to_page(pt)->count);
-       clear_bit(PG_locked, &virt_to_page(pt)->flags);
-       wake_up(&virt_to_page(pt)->wait);
+       
+       page = virt_to_page(pt);
+       atomic_dec(&page->count);
+       clear_bit(PG_locked, &page->flags);
+       wake_up(&page->wait);
        free_page((unsigned long) pt);
        atomic_dec(&agp_bridge.current_memory_agp);
 }
@@ -1092,6 +1106,8 @@ static int __init intel_i810_setup(struct pci_dev *i810_dev)
        agp_bridge.free_by_type = intel_i810_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -1243,6 +1259,10 @@ static unsigned long intel_mask_memory(unsigned long addr, int type)
        return addr | agp_bridge.masks[0].mask;
 }
 
+static void intel_resume(void)
+{
+       intel_configure();
+}
 
 /* Setup function */
 static gatt_mask intel_generic_masks[] =
@@ -1285,6 +1305,8 @@ static int __init intel_generic_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = intel_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -1316,6 +1338,8 @@ static int __init intel_840_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -1347,6 +1371,8 @@ static int __init intel_850_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -1465,6 +1491,8 @@ static int __init via_generic_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -1577,6 +1605,8 @@ static int __init sis_generic_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -1953,6 +1983,8 @@ static int __init amd_irongate_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = agp_generic_alloc_page;
        agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -2108,15 +2140,15 @@ static void ali_cache_flush(void)
 
 static unsigned long ali_alloc_page(void)
 {
-       void *pt;
+       struct page *page;
        u32 temp;
 
-       pt = (void *) __get_free_page(GFP_KERNEL);
-       if (pt == NULL)
+       page = alloc_page(GFP_KERNEL);
+       if (page == NULL)
                return 0;
 
-       atomic_inc(&virt_to_page(pt)->count);
-       set_bit(PG_locked, &virt_to_page(pt)->flags);
+       atomic_inc(&page->count);
+       set_bit(PG_locked, &page->flags);
        atomic_inc(&agp_bridge.current_memory_agp);
 
        global_cache_flush();
@@ -2125,16 +2157,17 @@ static unsigned long ali_alloc_page(void)
                pci_read_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL, &temp);
                pci_write_config_dword(agp_bridge.dev, ALI_CACHE_FLUSH_CTRL,
                                (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-                                 virt_to_phys((void *)pt)) |
+                                 virt_to_phys(page_address(page))) |
                                    ALI_CACHE_FLUSH_EN ));
        }
-       return (unsigned long) pt;
+       return (unsigned long)page_address(page);
 }
 
-static void ali_destroy_page(unsigned long page)
+static void ali_destroy_page(unsigned long addr)
 {
        u32 temp;
-       void *pt = (void *) page;
+       void *pt = (void *) addr;
+       struct page *page;
 
        if (pt == NULL)
                return;
@@ -2149,9 +2182,10 @@ static void ali_destroy_page(unsigned long page)
                                    ALI_CACHE_FLUSH_EN));
        }
 
-       atomic_dec(&virt_to_page(pt)->count);
-       clear_bit(PG_locked, &virt_to_page(pt)->flags);
-       wake_up(&virt_to_page(pt)->wait);
+       page = virt_to_page(pt);
+       atomic_dec(&page->count);
+       clear_bit(PG_locked, &page->flags);
+       wake_up(&page->wait);
        free_page((unsigned long) pt);
        atomic_dec(&agp_bridge.current_memory_agp);
 }
@@ -2197,6 +2231,8 @@ static int __init ali_generic_setup (struct pci_dev *pdev)
        agp_bridge.free_by_type = agp_generic_free_by_type;
        agp_bridge.agp_alloc_page = ali_alloc_page;
        agp_bridge.agp_destroy_page = ali_destroy_page;
+       agp_bridge.suspend = agp_generic_suspend;
+       agp_bridge.resume = agp_generic_resume;
        agp_bridge.cant_use_aperture = 0;
 
        return 0;
@@ -2410,7 +2446,7 @@ static int serverworks_fetch_size(void)
                              &temp);
        pci_write_config_dword(agp_bridge.dev,
                               serverworks_private.gart_addr_ofs,
-                              0xfe000000);
+                              SVWRKS_SIZE_MASK);
        pci_read_config_dword(agp_bridge.dev,
                              serverworks_private.gart_addr_ofs,
                              &temp2);
@@ -2895,11 +2931,11 @@ static struct {
                "AMD",
                "Irongate",
                amd_irongate_setup },
-       { PCI_DEVICE_ID_AMD_761_0,
+       { PCI_DEVICE_ID_AMD_762_0,
                PCI_VENDOR_ID_AMD,
-               AMD_761,
+               AMD_IRONGATE,
                "AMD",
-               "761",
+               "AMD 760MP",
                amd_irongate_setup },
        { 0,
                PCI_VENDOR_ID_AMD,
@@ -2952,6 +2988,7 @@ static struct {
                "Intel",
                "Generic",
                intel_generic_setup },
+
 #endif /* CONFIG_AGP_INTEL */
 
 #ifdef CONFIG_AGP_SIS
@@ -2979,29 +3016,11 @@ static struct {
                "SiS",
                "530",
                sis_generic_setup },
-       { PCI_DEVICE_ID_SI_630,
-               PCI_VENDOR_ID_SI,
-               SIS_GENERIC,
-               "SiS",
-               "Generic",
-               sis_generic_setup },
-       { PCI_DEVICE_ID_SI_540,
+       { PCI_DEVICE_ID_SI_735,
                PCI_VENDOR_ID_SI,
                SIS_GENERIC,
                "SiS",
-               "Generic",
-               sis_generic_setup },
-       { PCI_DEVICE_ID_SI_620,
-               PCI_VENDOR_ID_SI,
-               SIS_GENERIC,
-               "SiS",
-               "Generic",
-               sis_generic_setup },
-       { PCI_DEVICE_ID_SI_530,
-               PCI_VENDOR_ID_SI,
-               SIS_GENERIC,
-               "SiS",
-               "Generic",
+               "735",
                sis_generic_setup },
        { 0,
                PCI_VENDOR_ID_SI,
@@ -3048,6 +3067,12 @@ static struct {
                "Via",
                "Apollo Pro KT133",
                via_generic_setup },
+       { PCI_DEVICE_ID_VIA_8367_0,
+               PCI_VENDOR_ID_VIA,
+               VIA_APOLLO_KT133,
+               "Via",
+               "Apollo Pro KT266",
+               via_generic_setup },
        { 0,
                PCI_VENDOR_ID_VIA,
                VIA_GENERIC,
@@ -3372,7 +3397,7 @@ static int __init agp_backend_initialize(void)
        size_value = agp_bridge.fetch_size();
 
        if (size_value == 0) {
-               printk(KERN_ERR PFX "unable to detrimine aperture size.\n");
+               printk(KERN_ERR PFX "unable to determine aperture size.\n");
                rc = -EINVAL;
                goto err_out;
        }
@@ -3434,6 +3459,19 @@ static void agp_backend_cleanup(void)
        }
 }
 
+static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data)
+{
+       switch(rq)
+       {
+               case PM_SUSPEND:
+                       return agp_bridge.suspend();
+               case PM_RESUME:
+                       agp_bridge.resume();
+                       return 0;
+       }               
+       return 0;
+}
+
 extern int agp_frontend_initialize(void);
 extern void agp_frontend_cleanup(void);
 
@@ -3468,11 +3506,14 @@ static int __init agp_init(void)
        }
 
        inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
+       
+       pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power);
        return 0;
 }
 
 static void __exit agp_cleanup(void)
 {
+       pm_unregister_all(agp_power);
        agp_frontend_cleanup();
        agp_backend_cleanup();
        inter_module_unregister("drm_agp");
index f0a1255599beafa035bbc9e774c82d8244004f64..c9e609cea47ee30bb834ed6d23f228f2ad0846f2 100644 (file)
@@ -661,6 +661,7 @@ int vc_allocate(unsigned int currcons)      /* return 0 on success */
            p = (long) kmalloc(structsize, GFP_KERNEL);
            if (!p)
                return -ENOMEM;
+           memset((void *)p, 0, structsize);
            vc_cons[currcons].d = (struct vc_data *)p;
            vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
            visual_init(currcons, 1);
index a50cf0c236292d97e26a0f76299a934aa6dcee9a..0b8fe7d6d467417a5024f41194811ff0647f556f 100644 (file)
@@ -911,6 +911,10 @@ static void kbd_bh(unsigned long dummy)
 EXPORT_SYMBOL(keyboard_tasklet);
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 
+typedef void (pm_kbd_func) (void);
+
+pm_callback pm_kbd_request_override = NULL;
+
 int __init kbd_init(void)
 {
        int i;
@@ -934,7 +938,7 @@ int __init kbd_init(void)
        tasklet_enable(&keyboard_tasklet);
        tasklet_schedule(&keyboard_tasklet);
        
-       pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, NULL);
+       pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_kbd_request_override);
 
        return 0;
 }
index 69f0590ec34dd5a30b5daa435f34533094c038a7..c29923de6db1601764588d244fc9dcfd6587fc43 100644 (file)
@@ -397,6 +397,32 @@ char pckbd_unexpected_up(unsigned char keycode)
            return 0200;
 }
 
+void pckbd_pm_resume(void)
+{
+#if defined CONFIG_PSMOUSE
+       unsigned long flags;
+
+       if (queue) {                    /* Aux port detected */
+               if (aux_count == 0) {   /* Mouse not in use */ 
+                       spin_lock_irqsave(&kbd_controller_lock, flags);
+                       /*
+                        * Dell Lat. C600 A06 enables mouse after resume.
+                        * When user touches the pad, it posts IRQ 12
+                        * (which we do not process), thus holding keyboard.
+                        */
+                       kbd_write_command(KBD_CCMD_MOUSE_DISABLE);
+                       /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */
+                       kb_wait();
+                       kbd_write_command(KBD_CCMD_WRITE_MODE);
+                       kb_wait();
+                       kbd_write_output(AUX_INTS_OFF);
+                       spin_unlock_irqrestore(&kbd_controller_lock, flags);
+               }
+       }
+#endif       
+}
+
+
 static inline void handle_mouse_event(unsigned char scancode)
 {
 #ifdef CONFIG_PSMOUSE
@@ -521,7 +547,7 @@ static int send_data(unsigned char data)
                        mdelay(1);
                        if (!--timeout) {
 #ifdef KBD_REPORT_TIMEOUTS
-                               printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?\n");
+                               printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?(%02x)\n", data);
 #endif
                                return 0;
                        }
@@ -707,6 +733,53 @@ static void kbd_write_output_w(int data)
        spin_unlock_irqrestore(&kbd_controller_lock, flags);
 }
 
+#if defined(__alpha__)
+/*
+ * Some Alphas cannot mask some/all interrupts, so we have to
+ * make sure not to allow interrupts AT ALL when polling for
+ * specific return values from the keyboard.
+ *
+ * I think this should work on any architecture, but for now, only Alpha.
+ */
+static int kbd_write_command_w_and_wait(int data)
+{
+       unsigned long flags;
+       int input;
+
+       spin_lock_irqsave(&kbd_controller_lock, flags);
+       kb_wait();
+       kbd_write_command(data);
+       input = kbd_wait_for_input();
+       spin_unlock_irqrestore(&kbd_controller_lock, flags);
+       return input;
+}
+
+static int kbd_write_output_w_and_wait(int data)
+{
+       unsigned long flags;
+       int input;
+
+       spin_lock_irqsave(&kbd_controller_lock, flags);
+       kb_wait();
+       kbd_write_output(data);
+       input = kbd_wait_for_input();
+       spin_unlock_irqrestore(&kbd_controller_lock, flags);
+       return input;
+}
+#else
+static int kbd_write_command_w_and_wait(int data)
+{
+       kbd_write_command_w(data);
+       return kbd_wait_for_input();
+}
+
+static int kbd_write_output_w_and_wait(int data)
+{
+       kbd_write_output_w(data);
+       return kbd_wait_for_input();
+}
+#endif /* __alpha__ */
+
 #if defined CONFIG_PSMOUSE
 static void kbd_write_cmd(int cmd)
 {
@@ -790,8 +863,8 @@ static char * __init initialize_kbd(void)
                              | KBD_MODE_KCC);
 
        /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
-       kbd_write_command_w(KBD_CCMD_READ_MODE);
-       if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+       if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC))
+       {
                /*
                 * If the controller does not support conversion,
                 * Set the keyboard to scan-code set 1.
@@ -802,20 +875,16 @@ static char * __init initialize_kbd(void)
                kbd_wait_for_input();
        }
 
-       
-       kbd_write_output_w(KBD_CMD_ENABLE);
-       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+       if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK)
                return "Enable keyboard: no ACK";
 
        /*
         * Finally, set the typematic rate to maximum.
         */
-       kbd_write_output_w(KBD_CMD_SET_RATE);
-       if (kbd_wait_for_input() != KBD_REPLY_ACK)
-               return "Set rate: no ACK";
-       kbd_write_output_w(0x00);
-       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+       if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK)
                return "Set rate: no ACK";
+       if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK)
+               return "Set rate: no 2nd ACK";
 
        return NULL;
 }
@@ -1109,13 +1178,20 @@ static struct miscdevice psaux_mouse = {
 
 static int __init psaux_init(void)
 {
+       int retval;
+
        if (!detect_auxiliary_port())
                return -EIO;
 
-       misc_register(&psaux_mouse);
+       if ((retval = misc_register(&psaux_mouse)))
+               return retval;
+
        queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
-       if (queue == NULL)
-               panic("psaux_init(): out of memory");
+       if (queue == NULL) {
+               printk(KERN_ERR "psaux_init(): out of memory\n");
+               misc_deregister(&psaux_mouse);
+               return -ENOMEM;
+       }
        memset(queue, 0, sizeof(*queue));
        queue->head = queue->tail = 0;
        init_waitqueue_head(&queue->proc_list);
index aaca14148828b96d6ca7e230fa265ccc466b2b3e..40f0cb7deda7f299bf12e8cc30704e59f826b99b 100644 (file)
@@ -1591,12 +1591,9 @@ random_ioctl(struct inode * inode, struct file * file,
                        return -EPERM;
                p = (int *) arg;
                ent_count = random_state->entropy_count;
-               if (put_user(ent_count, p++))
-                       return -EFAULT;
-                       
-               if (get_user(size, p))
-                       return -EFAULT;
-               if (put_user(random_state->poolinfo.poolwords, p++))
+               if (put_user(ent_count, p++) ||
+                   get_user(size, p) ||
+                   put_user(random_state->poolinfo.poolwords, p++))
                        return -EFAULT;
                if (size < 0)
                        return -EINVAL;
@@ -1809,13 +1806,13 @@ static int uuid_strategy(ctl_table *table, int *name, int nlen,
        if (uuid[8] == 0)
                generate_random_uuid(uuid);
 
-       get_user(len, oldlenp);
+       if (get_user(len, oldlenp))
+               return -EFAULT;
        if (len) {
                if (len > 16)
                        len = 16;
-               if (copy_to_user(oldval, uuid, len))
-                       return -EFAULT;
-               if (put_user(len, oldlenp))
+               if (copy_to_user(oldval, uuid, len) ||
+                   put_user(len, oldlenp))
                        return -EFAULT;
        }
        return 1;
index 04b888a7c50b4692e3bf8cf50717f05ff8d96c03..41ae0a4ad33fd67846960a048a59db74ebc526de 100644 (file)
@@ -48,6 +48,7 @@ static int minor = -1;
 static int verbose; /* = 0 */
 static int fnkeyinit; /* = 0 */
 static int camera; /* = 0 */
+extern int is_sony_vaio_laptop; /* set in DMI table parse routines */
 
 /* Inits the queue */
 static inline void sonypi_initq(void) {
@@ -108,32 +109,23 @@ static inline int sonypi_emptyq(void) {
 }
 
 static void sonypi_ecrset(u16 addr, u16 value) {
-       int n = 100;
 
-       while (n-- && (inw_p(SONYPI_CST_IOPORT) & 3))
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 3);
        outw_p(0x81, SONYPI_CST_IOPORT);
-       while (inw_p(SONYPI_CST_IOPORT) & 2)
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
        outw_p(addr, SONYPI_DATA_IOPORT);
-       while (inw_p(SONYPI_CST_IOPORT) & 2)
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
        outw_p(value, SONYPI_DATA_IOPORT);
-       while (inw_p(SONYPI_CST_IOPORT) & 2)
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
 }
 
 static u16 sonypi_ecrget(u16 addr) {
-       int n = 100;
 
-       while (n-- && (inw_p(SONYPI_CST_IOPORT) & 3))
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 3);
        outw_p(0x80, SONYPI_CST_IOPORT);
-       while (inw_p(SONYPI_CST_IOPORT) & 2)
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
        outw_p(addr, SONYPI_DATA_IOPORT);
-       while (inw_p(SONYPI_CST_IOPORT) & 2)
-               udelay(1);
+       wait_on_command(inw_p(SONYPI_CST_IOPORT) & 2);
        return inw_p(SONYPI_DATA_IOPORT);
 }
 
@@ -189,8 +181,7 @@ static void __devexit sonypi_r505_dis(void) {
 static u8 sonypi_call1(u8 dev) {
        u8 v1, v2;
 
-       while (inb_p(sonypi_device.ioport2) & 2)
-               udelay(1);
+       wait_on_command(inb_p(sonypi_device.ioport2) & 2);
        outb(dev, sonypi_device.ioport2);
        v1 = inb_p(sonypi_device.ioport2);
        v2 = inb_p(sonypi_device.ioport1);
@@ -200,14 +191,10 @@ static u8 sonypi_call1(u8 dev) {
 static u8 sonypi_call2(u8 dev, u8 fn) {
        u8 v1;
 
-       while (inb_p(sonypi_device.ioport2) & 2)
-               udelay(1);
+       wait_on_command(inb_p(sonypi_device.ioport2) & 2);
        outb(dev, sonypi_device.ioport2);
-
-       while (inb_p(sonypi_device.ioport2) & 2)
-               udelay(1);
+       wait_on_command(inb_p(sonypi_device.ioport2) & 2);
        outb(fn, sonypi_device.ioport1);
-
        v1 = inb_p(sonypi_device.ioport1);
        return v1;
 }
@@ -215,18 +202,12 @@ static u8 sonypi_call2(u8 dev, u8 fn) {
 static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
        u8 v1;
 
-       while (inb_p(sonypi_device.ioport2) & 2)
-               udelay(1);
+       wait_on_command(inb_p(sonypi_device.ioport2) & 2);
        outb(dev, sonypi_device.ioport2);
-
-       while (inb_p(sonypi_device.ioport2) & 2)
-               udelay(1);
+       wait_on_command(inb_p(sonypi_device.ioport2) & 2);
        outb(fn, sonypi_device.ioport1);
-
-       while (inb_p(sonypi_device.ioport2) & 2)
-               udelay(1);
+       wait_on_command(inb_p(sonypi_device.ioport2) & 2);
        outb(v, sonypi_device.ioport1);
-
        v1 = inb_p(sonypi_device.ioport1);
        return v1;
 }
@@ -246,11 +227,8 @@ static u8 sonypi_read(u8 fn) {
 
 /* Set brightness, hue etc */
 static void sonypi_set(u8 fn, u8 v) {
-       int n = 100;
        
-       while (n--)
-               if (sonypi_call3(0x90, fn, v) == 0) 
-                       break;
+       wait_on_command(sonypi_call3(0x90, fn, v));
 }
 
 /* Tests if the camera is ready */
@@ -325,6 +303,13 @@ void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
        v1 = inb_p(sonypi_device.ioport1);
        v2 = inb_p(sonypi_device.ioport2);
 
+       if ((v2 & SONYPI_NORMAL_PKEY_EV) == SONYPI_NORMAL_PKEY_EV) {
+               for (i = 0; sonypi_pkeyev[i].event; i++)
+                       if (sonypi_pkeyev[i].data == v1) {
+                               event = sonypi_pkeyev[i].event;
+                               goto found;
+                       }
+       }
        if ((v2 & sonypi_jogger_ev) == sonypi_jogger_ev) {
                for (i = 0; sonypi_joggerev[i].event; i++)
                        if (sonypi_joggerev[i].data == v1) {
@@ -608,7 +593,7 @@ static int __devinit sonypi_probe(struct pci_dev *pcidev,
 
        for (i = 0; irq_list[i].irq; i++) {
                if (!request_irq(irq_list[i].irq, sonypi_irq, 
-                                SA_INTERRUPT, "sonypi", sonypi_irq)) {
+                                SA_SHIRQ, "sonypi", sonypi_irq)) {
                        sonypi_device.irq = irq_list[i].irq;
                        sonypi_device.bits = irq_list[i].bits;
                        break;
@@ -690,7 +675,10 @@ static struct pci_driver sonypi_driver = {
 };
 
 static int __init sonypi_init_module(void) {
-       return pci_module_init(&sonypi_driver);
+       if (is_sony_vaio_laptop)
+               return pci_module_init(&sonypi_driver);
+       else
+               return -ENODEV;
 }
 
 static void __exit sonypi_cleanup_module(void) {
@@ -703,6 +691,8 @@ module_exit(sonypi_cleanup_module);
 
 MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
 MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
+MODULE_LICENSE("GPL");
+
 
 MODULE_PARM(minor,"i");
 MODULE_PARM_DESC(minor, "minor number of the misc device, default is -1 (automatic)");
index 9160f0f6bdf20854d519ba4e73b14f14e00e47e5..023ae15d2ea69e4092167350041c0b591c994b31 100644 (file)
@@ -35,7 +35,7 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION     1
-#define SONYPI_DRIVER_MINORVERSION     2
+#define SONYPI_DRIVER_MINORVERSION     5
 
 #include <linux/types.h>
 #include <linux/pci.h>
@@ -138,6 +138,7 @@ static struct sonypi_irq_list sonypi_r505_irq_list[] = {
 #define SONYPI_NORMAL_FNKEY_EV 0x20
 #define SONYPI_R505_FNKEY_EV   0x08
 #define SONYPI_BLUETOOTH_EV    0x30
+#define SONYPI_NORMAL_PKEY_EV  0x40
 
 struct sonypi_event {
        u8      data;
@@ -189,6 +190,14 @@ static struct sonypi_event sonypi_fnkeyev[] = {
        { 0x00, 0x00 }
 };
 
+/* The set of possible program key events */
+static struct sonypi_event sonypi_pkeyev[] = {
+       { 0x01, SONYPI_EVENT_PKEY_P1 },
+       { 0x02, SONYPI_EVENT_PKEY_P2 },
+       { 0x04, SONYPI_EVENT_PKEY_P3 },
+       { 0x00, 0x00 }
+};
+
 /* The set of possible bluetooth events */
 static struct sonypi_event sonypi_blueev[] = {
        { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
@@ -223,6 +232,14 @@ struct sonypi_device {
        int model;
 };
 
+#define wait_on_command(command) { \
+       unsigned int n = 10000; \
+       while (--n && (command)) \
+               udelay(1); \
+       if (!n) \
+               printk(KERN_WARNING "sonypi command failed at " __FILE__ " : " __FUNCTION__ "(line %d)\n", __LINE__); \
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _SONYPI_PRIV_H_ */
index 9a31126aa0270db5da13d75068645db5c2a54479..8255927be9faf79b5627c2f037d0bf6fec89542b 100644 (file)
@@ -6,6 +6,10 @@
  *
  *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ *     overhauled to use key registration
+ *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
  */
 
 #include <linux/config.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 
+#include <linux/spinlock.h>
+
 #include <asm/ptrace.h>
 
+extern void wakeup_bdflush(int);
 extern void reset_vc(unsigned int);
 extern struct list_head super_blocks;
 
@@ -35,136 +42,83 @@ int sysrq_enabled = 1;
 /* Machine specific power off function */
 void (*sysrq_power_off)(void);
 
-EXPORT_SYMBOL(sysrq_power_off);
-
-/* Send a signal to all user processes */
+/* Loglevel sysrq handler */
+static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       int i;
+       i = key - '0';
+       console_loglevel = 7;
+       printk("%d\n", i);
+       console_loglevel = i;
+}      
+static struct sysrq_key_op sysrq_loglevel_op = {
+       handler:        sysrq_handle_loglevel,
+       help_msg:       "loglevel0-8",
+       action_msg:     "Loglevel set to ",
+};
 
-static void send_sig_all(int sig, int even_init)
-{
-       struct task_struct *p;
 
-       for_each_task(p) {
-               if (p->mm) {                                /* Not swapper nor kernel thread */
-                       if (p->pid == 1 && even_init)       /* Ugly hack to kill init */
-                               p->pid = 0x8000;
-                       force_sig(sig, p);
-               }
-       }
+/* SAK sysrq handler */
+#ifdef CONFIG_VT
+static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       if (tty)
+               do_SAK(tty);
+       reset_vc(fg_console);
 }
+static struct sysrq_key_op sysrq_SAK_op = {
+       handler:        sysrq_handle_SAK,
+       help_msg:       "saK",
+       action_msg:     "SAK\n",
+};
+#endif
 
-/*
- * This function is called by the keyboard handler when SysRq is pressed
- * and any other keycode arrives.
- */
 
-void handle_sysrq(int key, struct pt_regs *pt_regs,
-                 struct kbd_struct *kbd, struct tty_struct *tty)
-{
-       int orig_log_level = console_loglevel;
+/* unraw sysrq handler */
+static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       if (kbd)
+               kbd->kbdmode = VC_XLATE;
+}
+static struct sysrq_key_op sysrq_unraw_op = {
+       handler:        sysrq_handle_unraw,
+       help_msg:       "unRaw",
+       action_msg:     "Keyboard mode set to XLATE\n",
+};
 
-       if (!sysrq_enabled)
-               return;
 
-       if (!key)
-               return;
+/* reboot sysrq handler */
+static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       machine_restart(NULL);
+}
+static struct sysrq_key_op sysrq_reboot_op = {
+       handler:        sysrq_handle_reboot,
+       help_msg:       "reBoot",
+       action_msg:     "Resetting\n",
+};
 
-       console_loglevel = 7;
-       printk(KERN_INFO "SysRq: ");
-       switch (key) {
-       case 'r':                                           /* R -- Reset raw mode */
-               if (kbd) {
-                       kbd->kbdmode = VC_XLATE;
-                       printk("Keyboard mode set to XLATE\n");
-               }
-               break;
-#ifdef CONFIG_VT
-       case 'k':                                           /* K -- SAK */
-               printk("SAK\n");
-               if (tty)
-                       do_SAK(tty);
-               reset_vc(fg_console);
-               break;
-#endif
-       case 'b':                                           /* B -- boot immediately */
-               printk("Resetting\n");
-               machine_restart(NULL);
-               break;
-       case 'o':                                           /* O -- power off */
-               if (sysrq_power_off) {
-                       printk("Power off\n");
-                       sysrq_power_off();
-               }
-               break;
-       case 's':                                           /* S -- emergency sync */
-               printk("Emergency Sync\n");
-               emergency_sync_scheduled = EMERG_SYNC;
-               wakeup_bdflush();
-               break;
-       case 'u':                                           /* U -- emergency remount R/O */
-               printk("Emergency Remount R/O\n");
-               emergency_sync_scheduled = EMERG_REMOUNT;
-               wakeup_bdflush();
-               break;
-       case 'p':                                           /* P -- show PC */
-               printk("Show Regs\n");
-               if (pt_regs)
-                       show_regs(pt_regs);
-               break;
-       case 't':                                           /* T -- show task info */
-               printk("Show State\n");
-               show_state();
-               break;
-       case 'm':                                           /* M -- show memory info */
-               printk("Show Memory\n");
-               show_mem();
-               break;
-       case '0' ... '9':                                   /* 0-9 -- set console logging level */
-               orig_log_level = key - '0';
-               printk("Log level set to %d\n", orig_log_level);
-               break;
-       case 'e':                                           /* E -- terminate all user processes */
-               printk("Terminate All Tasks\n");
-               send_sig_all(SIGTERM, 0);
-               orig_log_level = 8;                         /* We probably have killed syslogd */
-               break;
-       case 'i':                                           /* I -- kill all user processes */
-               printk("Kill All Tasks\n");
-               send_sig_all(SIGKILL, 0);
-               orig_log_level = 8;
-               break;
-       case 'l':                                           /* L -- kill all processes including init */
-               printk("Kill ALL Tasks (even init)\n");
-               send_sig_all(SIGKILL, 1);
-               orig_log_level = 8;
-               break;
-       default:                                            /* Unknown: help */
-               if (kbd)
-                       printk("unRaw ");
-#ifdef CONFIG_VT
-               if (tty)
-                       printk("saK ");
-#endif
-               printk("Boot ");
-               if (sysrq_power_off)
-                       printk("Off ");
-               printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n");
-               /* Don't use 'A' as it's handled specially on the Sparc */
-       }
 
-       console_loglevel = orig_log_level;
-}
 
-/* Aux routines for the syncer */
+/* SYNC SYSRQ HANDLERS BLOCK */
 
-static int is_local_disk(kdev_t dev)       /* Guess if the device is a local hard drive */
-{
-       unsigned int major = MAJOR(dev);
+/* do_emergency_sync helper function */
+/* Guesses if the device is a local hard drive */
+static int is_local_disk(kdev_t dev) {
+       unsigned int major;
+       major = MAJOR(dev);
 
        switch (major) {
        case IDE0_MAJOR:
        case IDE1_MAJOR:
        case IDE2_MAJOR:
        case IDE3_MAJOR:
+       case IDE4_MAJOR:
+       case IDE5_MAJOR:
+       case IDE6_MAJOR:
+       case IDE7_MAJOR:
+       case IDE8_MAJOR:
+       case IDE9_MAJOR:
        case SCSI_DISK0_MAJOR:
        case SCSI_DISK1_MAJOR:
        case SCSI_DISK2_MAJOR:
@@ -173,19 +127,24 @@ static int is_local_disk(kdev_t dev)          /* Guess if the device is a local hard
        case SCSI_DISK5_MAJOR:
        case SCSI_DISK6_MAJOR:
        case SCSI_DISK7_MAJOR:
+       case XT_DISK_MAJOR:
                return 1;
        default:
                return 0;
        }
 }
 
+/* do_emergency_sync helper function */
 static void go_sync(struct super_block *sb, int remount_flag)
 {
+       int orig_loglevel;
+       orig_loglevel = console_loglevel;
+       console_loglevel = 7;
        printk(KERN_INFO "%sing device %s ... ",
               remount_flag ? "Remount" : "Sync",
               kdevname(sb->s_dev));
 
-       if (remount_flag) {                                 /* Remount R/O */
+       if (remount_flag) { /* Remount R/O */
                int ret, flags;
                struct list_head *p;
 
@@ -215,12 +174,12 @@ static void go_sync(struct super_block *sb, int remount_flag)
                        }
                } else
                        printk("nothing to do\n");
-       } else {
-               fsync_dev(sb->s_dev);                       /* Sync only */
+       } else { /* Sync only */
+               fsync_dev(sb->s_dev);
                printk("OK\n");
        }
+       console_loglevel = orig_loglevel;
 }
-
 /*
  * Emergency Sync or Unmount. We cannot do it directly, so we set a special
  * flag and wake up the bdflush kernel thread which immediately calls this function.
@@ -230,10 +189,10 @@ static void go_sync(struct super_block *sb, int remount_flag)
 
 int emergency_sync_scheduled;
 
-void do_emergency_sync(void)
-{
+void do_emergency_sync(void) {
        struct super_block *sb;
        int remount_flag;
+       int orig_loglevel;
 
        lock_kernel();
        remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
@@ -252,5 +211,277 @@ void do_emergency_sync(void)
                        go_sync(sb, remount_flag);
 
        unlock_kernel();
+
+       orig_loglevel = console_loglevel;
+       console_loglevel = 7;
        printk(KERN_INFO "Done.\n");
+       console_loglevel = orig_loglevel;
+}
+
+static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       emergency_sync_scheduled = EMERG_SYNC;
+       wakeup_bdflush(0);
+}
+static struct sysrq_key_op sysrq_sync_op = {
+       handler:        sysrq_handle_sync,
+       help_msg:       "Sync",
+       action_msg:     "Emergency Sync\n",
+};
+
+static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       emergency_sync_scheduled = EMERG_REMOUNT;
+       wakeup_bdflush(0);
+}
+static struct sysrq_key_op sysrq_mountro_op = {
+       handler:        sysrq_handle_mountro,
+       help_msg:       "Unmount",
+       action_msg:     "Emergency Remount R/0\n",
+};
+
+/* END SYNC SYSRQ HANDLERS BLOCK */
+
+
+/* SHOW SYSRQ HANDLERS BLOCK */
+
+static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       if (pt_regs)
+               show_regs(pt_regs);
+}
+static struct sysrq_key_op sysrq_showregs_op = {
+       handler:        sysrq_handle_showregs,
+       help_msg:       "showPc",
+       action_msg:     "Show Regs\n",
+};
+
+
+static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       show_state();
+}
+static struct sysrq_key_op sysrq_showstate_op = {
+       handler:        sysrq_handle_showstate,
+       help_msg:       "showTasks",
+       action_msg:     "Show State\n",
+};
+
+
+static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       show_mem();
+}
+static struct sysrq_key_op sysrq_showmem_op = {
+       handler:        sysrq_handle_showmem,
+       help_msg:       "showMem",
+       action_msg:     "Show Memory\n",
+};
+
+/* SHOW SYSRQ HANDLERS BLOCK */
+
+
+/* SIGNAL SYSRQ HANDLERS BLOCK */
+
+/* signal sysrq helper function
+ * Sends a signal to all user processes */
+static void send_sig_all(int sig, int even_init)
+{
+       struct task_struct *p;
+
+       for_each_task(p) {
+               if (p->mm) { /* Not swapper nor kernel thread */
+                       if (p->pid == 1 && even_init)
+                               /* Ugly hack to kill init */
+                               p->pid = 0x8000;
+                       if (p->pid != 1)
+                               force_sig(sig, p);
+               }
+       }
+}
+
+static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       send_sig_all(SIGTERM, 0);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_term_op = {
+       handler:        sysrq_handle_term,
+       help_msg:       "tErm",
+       action_msg:     "Terminate All Tasks\n",
+};
+
+static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       send_sig_all(SIGKILL, 0);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_kill_op = {
+       handler:        sysrq_handle_kill,
+       help_msg:       "kIll",
+       action_msg:     "Kill All Tasks\n",
+};
+
+static void sysrq_handle_killall(int key, struct pt_regs *pt_regs,
+               struct kbd_struct *kbd, struct tty_struct *tty) {
+       send_sig_all(SIGKILL, 1);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_killall_op = {
+       handler:        sysrq_handle_killall,
+       help_msg:       "killalL",
+       action_msg:     "Kill All Tasks (even init)\n",
+};
+
+/* END SIGNAL SYSRQ HANDLERS BLOCK */
+
+
+/* Key Operations table and lock */
+spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED;
+#define SYSRQ_KEY_TABLE_LENGTH 36
+static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
+/* 0 */        &sysrq_loglevel_op,
+/* 1 */        &sysrq_loglevel_op,
+/* 2 */        &sysrq_loglevel_op,
+/* 3 */        &sysrq_loglevel_op,
+/* 4 */        &sysrq_loglevel_op,
+/* 5 */        &sysrq_loglevel_op,
+/* 6 */        &sysrq_loglevel_op,
+/* 7 */        &sysrq_loglevel_op,
+/* 8 */        &sysrq_loglevel_op,
+/* 9 */        &sysrq_loglevel_op,
+/* a */        NULL, /* Don't use for system provided sysrqs,
+                it is handled specially on the spark
+                and will never arive */
+/* b */        &sysrq_reboot_op,
+/* c */        NULL,
+/* d */        NULL,
+/* e */        &sysrq_term_op,
+/* f */        NULL,
+/* g */        NULL,
+/* h */        NULL,
+/* i */        &sysrq_kill_op,
+/* j */        NULL,
+#ifdef CONFIG_VT
+/* k */        &sysrq_SAK_op,
+#else
+/* k */        NULL,
+#endif
+/* l */        &sysrq_killall_op,
+/* m */        &sysrq_showmem_op,
+/* n */        NULL,
+/* o */        NULL, /* This will often be registered
+                as 'Off' at init time */
+/* p */        &sysrq_showregs_op,
+/* q */        NULL,
+/* r */        &sysrq_unraw_op,
+/* s */        &sysrq_sync_op,
+/* t */        &sysrq_showstate_op,
+/* u */        &sysrq_mountro_op,
+/* v */        NULL,
+/* w */        NULL,
+/* x */        NULL,
+/* w */        NULL,
+/* z */        NULL
+};
+
+/* key2index calculation, -1 on invalid index */
+static __inline__ int sysrq_key_table_key2index(int key) {
+       int retval;
+       if ((key >= '0') & (key <= '9')) {
+               retval = key - '0';
+       } else if ((key >= 'a') & (key <= 'z')) {
+               retval = key + 10 - 'a';
+       } else {
+               retval = -1;
+       }
+       return retval;
+}
+
+/*
+ * table lock and unlocking functions, exposed to modules
+ */
+
+void __sysrq_lock_table (void) { spin_lock(&sysrq_key_table_lock); }
+
+void __sysrq_unlock_table (void) { spin_unlock(&sysrq_key_table_lock); }
+
+/*
+ * get and put functions for the table, exposed to modules.
+ */
+
+struct sysrq_key_op *__sysrq_get_key_op (int key) {
+        struct sysrq_key_op *op_p;
+        int i;
+       
+       i = sysrq_key_table_key2index(key);
+        op_p = (i == -1) ? NULL : sysrq_key_table[i];
+        return op_p;
+}
+
+void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
+        int i;
+
+       i = sysrq_key_table_key2index(key);
+        if (i != -1)
+                sysrq_key_table[i] = op_p;
+}
+
+/*
+ * This function is called by the keyboard handler when SysRq is pressed
+ * and any other keycode arrives.
+ */
+
+void handle_sysrq(int key, struct pt_regs *pt_regs,
+                 struct kbd_struct *kbd, struct tty_struct *tty) {
+       if (!sysrq_enabled)
+               return;
+
+       __sysrq_lock_table();
+       __handle_sysrq_nolock(key, pt_regs, kbd, tty);
+       __sysrq_unlock_table();
 }
+
+/*
+ * This is the non-locking version of handle_sysrq
+ * It must/can only be called by sysrq key handlers,
+ * as they are inside of the lock
+ */
+
+void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs,
+                 struct kbd_struct *kbd, struct tty_struct *tty) {
+       struct sysrq_key_op *op_p;
+       int orig_log_level;
+       int i, j;
+       
+       if (!sysrq_enabled)
+               return;
+
+       orig_log_level = console_loglevel;
+       console_loglevel = 7;
+       printk(KERN_INFO "SysRq : ");
+
+        op_p = __sysrq_get_key_op(key);
+        if (op_p) {
+                printk ("%s", op_p->action_msg);
+                op_p->handler(key, pt_regs, kbd, tty);
+       } else {
+               printk("HELP : ");
+               /* Only print the help msg once per handler */
+               for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) 
+               if (sysrq_key_table[i]) {
+                       for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
+                       if (j == i)
+                               printk ("%s ", sysrq_key_table[i]->help_msg);
+               }
+               printk ("\n");
+       }
+       console_loglevel = orig_log_level;
+}
+
+EXPORT_SYMBOL(handle_sysrq);
+EXPORT_SYMBOL(__handle_sysrq_nolock);
+EXPORT_SYMBOL(__sysrq_lock_table);
+EXPORT_SYMBOL(__sysrq_unlock_table);
+EXPORT_SYMBOL(__sysrq_get_key_op);
+EXPORT_SYMBOL(__sysrq_put_key_op);
index 2946ec1a9c71854942b7c6588e073134f333dcf5..f8c1b6c759e46cf4e5e5144fef5fab537eb9f35e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/fcntl.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/bitops.h>
 #undef TTY_DEBUG_WAIT_UNTIL_SENT
 
 #undef DEBUG
-#ifdef DEBUG
-# define       PRINTK(x)       printk (x)
-#else
-# define       PRINTK(x)       /**/
-#endif
 
 /*
  * Internal flag options for termios setting behavior
@@ -145,18 +141,19 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
 static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
 {
        struct termios tmp_termios;
-       int retval;
+       int retval = tty_check_change(tty);
 
-       retval = tty_check_change(tty);
        if (retval)
                return retval;
 
        if (opt & TERMIOS_TERMIO) {
                memcpy(&tmp_termios, tty->termios, sizeof(struct termios));
-               if (user_termio_to_kernel_termios(&tmp_termios, (struct termio *) arg))
+               if (user_termio_to_kernel_termios(&tmp_termios,
+                                                 (struct termio *) arg))
                        return -EFAULT;
        } else {
-               if (user_termios_to_kernel_termios(&tmp_termios, (struct termios *) arg))
+               if (user_termios_to_kernel_termios(&tmp_termios,
+                                                  (struct termios *) arg))
                        return -EFAULT;
        }
 
@@ -232,9 +229,7 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
        tmp.sg_erase = tty->termios->c_cc[VERASE];
        tmp.sg_kill = tty->termios->c_cc[VKILL];
        tmp.sg_flags = get_sgflags(tty);
-       if (copy_to_user(sgttyb, &tmp, sizeof(tmp)))
-               return -EFAULT;
-       return 0;
+       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 static void set_sgflags(struct termios * termios, int flags)
@@ -247,7 +242,8 @@ static void set_sgflags(struct termios * termios, int flags)
                termios->c_lflag &= ~ICANON;
        }
        if (flags & 0x08) {             /* echo */
-               termios->c_lflag |= ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
+               termios->c_lflag |= ECHO | ECHOE | ECHOK |
+                                   ECHOCTL | ECHOKE | IEXTEN;
        }
        if (flags & 0x10) {             /* crmod */
                termios->c_oflag |= OPOST | ONLCR;
@@ -293,9 +289,7 @@ static int get_tchars(struct tty_struct * tty, struct tchars * tchars)
        tmp.t_stopc = tty->termios->c_cc[VSTOP];
        tmp.t_eofc = tty->termios->c_cc[VEOF];
        tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
-       if (copy_to_user(tchars, &tmp, sizeof(tmp)))
-               return -EFAULT;
-       return 0;
+       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 static int set_tchars(struct tty_struct * tty, struct tchars * tchars)
@@ -325,9 +319,7 @@ static int get_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
        tmp.t_flushc = tty->termios->c_cc[VEOL2];       /* what is flushc anyway? */
        tmp.t_werasc = tty->termios->c_cc[VWERASE];
        tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
-       if (copy_to_user(ltchars, &tmp, sizeof(tmp)))
-               return -EFAULT;
-       return 0;
+       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 static int set_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
@@ -480,7 +472,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        return 0;
 
                case TIOCSLCKTRMIOS:
-                       if (!suser())
+                       if (!capable(CAP_SYS_ADMIN))
                                return -EPERM;
                        if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios *) arg))
                                return -EFAULT;
@@ -493,9 +485,8 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
                            tty->driver.subtype != PTY_TYPE_MASTER)
                                return -ENOTTY;
-                       retval = get_user(pktmode, (int *) arg);
-                       if (retval)
-                               return retval;
+                       if (get_user(pktmode, (int *) arg))
+                               return -EFAULT;
                        if (pktmode) {
                                if (!tty->packet) {
                                        tty->packet = 1;
@@ -508,9 +499,8 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                case TIOCGSOFTCAR:
                        return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
                case TIOCSSOFTCAR:
-                       retval = get_user(arg, (unsigned int *) arg);
-                       if (retval)
-                               return retval;
+                       if (get_user(arg, (unsigned int *) arg))
+                               return -EFAULT;
                        tty->termios->c_cflag =
                                ((tty->termios->c_cflag & ~CLOCAL) |
                                 (arg ? CLOCAL : 0));
@@ -519,3 +509,5 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        return -ENOIOCTLCMD;
                }
 }
+
+EXPORT_SYMBOL(n_tty_ioctl);
index e15c3505c8241f382dc353669e5f89923c1e6ceb..7ac43811db5a2cd7fc8a8ffb6f06ae704c671051 100644 (file)
@@ -92,8 +92,9 @@ unsigned int video_scan_lines;
  */
 
 #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
-    || (defined(__mips__) && !defined(CONFIG_SGI_IP22)) \
-    || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE))
+    || (defined(__mips__) && defined(CONFIG_ISA)) \
+    || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \
+    || defined(__x86_64__)
 
 static void
 kd_nosound(unsigned long ignored)
index 6b18bb68902f4a60eaa6b6875d93dd3e4104787d..6fb2d25281ac37b39d96ddebcb7c66ca2f8c6f13 100644 (file)
@@ -188,4 +188,8 @@ else
    define_bool CONFIG_BLK_DEV_IDE_MODES n
 fi
 
+dep_tristate 'Support for IDE Raid controllers' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
+dep_tristate '   Support Promise software RAID (Fasttrak(tm))' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate '   Highpoint 370 software RAID' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+
 endmenu
index 5362682d271dbd8990a7a65cf37cf0aa56703845..b6d3b424213fae8d129ff149dcfba31bf5e4d4e2 100644 (file)
@@ -66,6 +66,12 @@ ide-obj-$(CONFIG_BLK_DEV_TRM290)     += trm290.o
 ide-obj-$(CONFIG_BLK_DEV_UMC8672)      += umc8672.o
 ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)    += via82cxxx.o
 
+# The virtualised raid layers MUST come after the ide itself or bad stuff
+# will happen.
+obj-$(CONFIG_BLK_DEV_ATARAID)  += ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_PDC)      += pdcraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_HPT)      += hptraid.o
+
 ide-obj-$(CONFIG_PROC_FS)              += ide-proc.o
 
 ide-mod-objs           := $(export-objs) $(ide-obj-y)
diff --git a/drivers/ide/ataraid.c b/drivers/ide/ataraid.c
new file mode 100644 (file)
index 0000000..49521c0
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors:    Arjan van de Ven <arjanv@redhat.com>
+               
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+#include <linux/kdev_t.h>
+#include <linux/swap.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+                                        
+static int ataraid_hardsect_size[256];
+static int ataraid_blksize_size[256];
+
+static struct raid_device_operations* ataraid_ops[16];
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int ataraid_open(struct inode * inode, struct file * filp);
+static int ataraid_release(struct inode * inode, struct file * filp);
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+struct gendisk ataraid_gendisk;
+static int ataraid_gendisk_sizes[256];
+static int ataraid_readahead[256];
+
+static struct block_device_operations ataraid_fops = {
+       open:                   ataraid_open,
+       release:                ataraid_release,
+       ioctl:                  ataraid_ioctl,
+};
+                
+
+
+static DECLARE_MUTEX(ataraid_sem);
+
+/* Bitmap for the devices currently in use */
+static unsigned int ataraiduse;
+
+/* structure for the splitting of bufferheads */
+
+struct ataraid_bh_private {
+       struct buffer_head *parent;
+       atomic_t count;
+};
+
+/* stub fops functions */
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
+{
+       int minor;
+       minor = MINOR(inode->i_rdev)>>SHIFT;
+       
+       if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
+               return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
+       return -EINVAL;
+}
+
+static int ataraid_open(struct inode * inode, struct file * filp)
+{
+       int minor;
+       minor = MINOR(inode->i_rdev)>>SHIFT;
+
+       if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
+               return (ataraid_ops[minor]->open)(inode,filp);
+       return -EINVAL;
+}
+
+
+static int ataraid_release(struct inode * inode, struct file * filp)
+{
+       int minor;
+       minor = MINOR(inode->i_rdev)>>SHIFT;
+
+       if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
+               return (ataraid_ops[minor]->release)(inode,filp);
+       return -EINVAL;
+}
+
+static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+       int minor;
+       int retval;
+       minor = MINOR(bh->b_rdev)>>SHIFT;
+
+       if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
+               
+               retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
+               if (retval == -1) {
+                       ataraid_split_request(q,rw,bh);         
+                       return 0;
+               } else
+                       return retval;
+       }
+       return -EINVAL;
+}
+
+static struct buffer_head *get_bhead(void)
+{
+       void *ptr = NULL;
+       while (!ptr) {
+               ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
+               if (!ptr) {
+                       __set_current_state(TASK_RUNNING);
+                       current->policy |= SCHED_YIELD;
+                       schedule();             
+               }
+       }
+       return ptr;
+}
+
+static struct ataraid_bh_private *get_private(void)
+{
+       void *ptr = NULL;
+       while (!ptr) {
+               ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
+               if (!ptr) {
+                       __set_current_state(TASK_RUNNING);
+                       current->policy |= SCHED_YIELD;
+                       schedule();             
+               }
+       }
+       return ptr;
+}
+
+static void ataraid_end_request(struct buffer_head *bh, int uptodate)
+{
+       struct ataraid_bh_private *private = bh->b_private;
+
+       if (private==NULL)
+               BUG();
+
+       if (atomic_dec_and_test(&private->count)) {
+               private->parent->b_end_io(private->parent,uptodate);
+               private->parent = NULL;
+               kfree(private);
+       }
+       kfree(bh);
+}
+
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+       struct buffer_head *bh1,*bh2;
+       struct ataraid_bh_private *private;
+       bh1=get_bhead();
+       bh2=get_bhead();
+
+       /* If either of those ever fails we're doomed */
+       if ((!bh1)||(!bh2))
+               BUG();
+       private = get_private();
+       if (private==NULL)
+               BUG();
+       
+       memcpy(bh1, bh, sizeof(*bh));
+       memcpy(bh2, bh, sizeof(*bh));
+       
+       bh1->b_end_io = ataraid_end_request;
+       bh2->b_end_io = ataraid_end_request;
+
+       bh2->b_rsector += bh->b_size >> 10;
+       bh1->b_size /= 2;
+       bh2->b_size /= 2;
+       private->parent = bh;
+
+       bh1->b_private = private;
+       bh2->b_private = private;
+       atomic_set(&private->count,2);
+
+       bh2->b_data +=  bh->b_size/2;
+
+       generic_make_request(rw,bh1);
+       generic_make_request(rw,bh2);
+}
+
+
+
+
+/* device register / release functions */
+
+
+int ataraid_get_device(struct raid_device_operations *fops)
+{
+       int bit;
+       MOD_INC_USE_COUNT;
+       down(&ataraid_sem);
+       if (ataraiduse==~0U) {
+               up(&ataraid_sem);
+               MOD_DEC_USE_COUNT;
+               return -ENODEV;
+       }
+       bit=ffz(ataraiduse); 
+       ataraiduse |= 1<<bit;
+       ataraid_ops[bit] = fops;
+       up(&ataraid_sem);
+       return bit;
+}
+
+void ataraid_release_device(int device)
+{
+       down(&ataraid_sem);
+       
+       if ((ataraiduse & (1<<device))==0)
+               BUG();  /* device wasn't registered at all */
+       
+       ataraiduse &= ~(1<<device);
+       ataraid_ops[device] = NULL;
+       up(&ataraid_sem);
+       MOD_DEC_USE_COUNT;
+}
+
+void ataraid_register_disk(int device,long size)
+{
+       register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
+               &ataraid_fops,size);
+
+}
+
+static __init int ataraid_init(void) 
+{
+       int i;
+        for(i=0;i<256;i++)
+       {
+               ataraid_hardsect_size[i] = 512;
+               ataraid_blksize_size[i] = 1024;  
+               ataraid_readahead[i] = 32;
+       }
+       
+       if (blksize_size[ATAMAJOR]==NULL)
+               blksize_size[ATAMAJOR] = ataraid_blksize_size;
+       if (hardsect_size[ATAMAJOR]==NULL)
+               hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
+       
+       
+       /* setup the gendisk structure */       
+       ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
+       if (ataraid_gendisk.part==NULL) {
+               printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
+               return -1;
+       }
+       
+       memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
+       
+       
+       ataraid_gendisk.major       = ATAMAJOR;
+       ataraid_gendisk.major_name  = "ataraid";
+       ataraid_gendisk.minor_shift = 4;
+       ataraid_gendisk.max_p       = 15;
+       ataraid_gendisk.sizes       = &ataraid_gendisk_sizes[0];
+       ataraid_gendisk.nr_real     = 16;
+       ataraid_gendisk.fops        = &ataraid_fops;
+       
+       
+       add_gendisk(&ataraid_gendisk);
+                       
+       if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
+               printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
+               return -1;
+       }
+       
+                       
+       
+       blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
+                                                                                       
+       return 0;                                                               
+}
+
+
+static void __exit ataraid_exit(void)
+{
+       unregister_blkdev(ATAMAJOR, "ataraid");
+       hardsect_size[ATAMAJOR] = NULL;
+       blk_size[ATAMAJOR] = NULL;
+       blksize_size[ATAMAJOR] = NULL;                       
+       max_readahead[ATAMAJOR] = NULL;
+
+       del_gendisk(&ataraid_gendisk);
+        
+       if (ataraid_gendisk.part) {
+               kfree(ataraid_gendisk.part);
+               ataraid_gendisk.part = NULL;
+       }
+}
+
+module_init(ataraid_init);
+module_exit(ataraid_exit);
+
+
+
+EXPORT_SYMBOL(ataraid_get_device);
+EXPORT_SYMBOL(ataraid_release_device);
+EXPORT_SYMBOL(ataraid_gendisk);
+EXPORT_SYMBOL(ataraid_register_disk);
+
diff --git a/drivers/ide/ataraid.h b/drivers/ide/ataraid.h
new file mode 100644 (file)
index 0000000..3e909c0
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors:    Arjan van de Ven <arjanv@redhat.com>
+               
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#define ATAMAJOR 114
+#define SHIFT 4
+#define MINOR_MASK 15
+#define MAJOR_MASK 15
+
+                                        
+/* raid_device_operations is a light struct block_device_operations with an
+   added method for make_request */
+struct raid_device_operations {
+       int (*open) (struct inode *, struct file *);
+       int (*release) (struct inode *, struct file *);
+       int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+       int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
+};
+
+
+struct geom {
+       unsigned char heads;
+       unsigned int cylinders;
+       unsigned char sectors;
+};
+
+
+extern struct gendisk ataraid_gendisk;
+
+extern int ataraid_get_device(struct raid_device_operations *fops);
+extern void ataraid_release_device(int device);
+extern int get_blocksize(kdev_t dev);
+extern void ataraid_register_disk(int device,long size);
+
diff --git a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c
new file mode 100644 (file)
index 0000000..d70fab9
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors:    Arjan van de Ven <arjanv@redhat.com>
+
+   Based on work
+       Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
+       Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int hptraid_open(struct inode * inode, struct file * filp);
+static int hptraid_release(struct inode * inode, struct file * filp);
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+
+struct hptdisk {
+       kdev_t  device;
+       unsigned long sectors;
+       struct block_device *bdev;
+};
+
+struct hptraid {
+       unsigned int stride;
+       unsigned int disks;
+       unsigned long sectors;
+       struct geom geom;
+       
+       struct hptdisk disk[8];
+       
+       unsigned long cutoff[8];
+       unsigned int cutoff_disks[8];   
+};
+
+static struct raid_device_operations hptraid_ops = {
+       open:                   hptraid_open,
+       release:                hptraid_release,
+       ioctl:                  hptraid_ioctl,
+       make_request:           hptraid_make_request
+};
+
+static struct hptraid raid[16];
+
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor;
+       unsigned char val;
+       unsigned long sectors;
+       
+       if (!inode || !inode->i_rdev)   
+               return -EINVAL;
+
+       minor = MINOR(inode->i_rdev)>>SHIFT;
+       
+       switch (cmd) {
+               case BLKGETSIZE:   /* Return device size */
+                       if (!arg)  return -EINVAL;
+                       sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+                       if (MINOR(inode->i_rdev)&15)
+                               return put_user(sectors, (long *) arg);
+                       return put_user(raid[minor].sectors , (long *) arg);
+                       break;
+                       
+
+               case HDIO_GETGEO:
+               {
+                       struct hd_geometry *loc = (struct hd_geometry *) arg;
+                       unsigned short bios_cyl;
+                       
+                       if (!loc) return -EINVAL;
+                       val = 255;
+                       if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+                       val=63;
+                       if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+                       bios_cyl = raid[minor].sectors/63/255;
+                       if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+                       if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+                               (unsigned long *) &loc->start)) return -EFAULT;
+                       return 0;
+               }
+
+               case HDIO_GETGEO_BIG:
+               {
+                       struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+                       unsigned int bios_cyl;
+                       if (!loc) return -EINVAL;
+                       val = 255;
+                       if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+                       val = 63;
+                       if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+                       bios_cyl = raid[minor].sectors/63/255;
+                       if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+                       if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+                               (unsigned long *) &loc->start)) return -EFAULT;
+                       return 0;
+               }
+                       
+               case BLKROSET:
+               case BLKROGET:
+               case BLKSSZGET:
+                       return blk_ioctl(inode->i_rdev, cmd, arg);
+
+               default:
+                       return -EINVAL;
+       };
+
+       return 0;
+}
+
+
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+       unsigned long rsect;
+       unsigned long rsect_left,rsect_accum = 0;
+       unsigned long block;
+       unsigned int disk=0,real_disk=0;
+       int i;
+       int device;
+       struct hptraid *thisraid;
+
+       rsect = bh->b_rsector;
+
+       /* Ok. We need to modify this sector number to a new disk + new sector number. 
+        * If there are disks of different sizes, this gets tricky. 
+        * Example with 3 disks (1Gb, 4Gb and 5 GB):
+        * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+        * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+        * and the last 1Gb is disk 3 only.
+        *
+        * the way this is solved is like this: We have a list of "cutoff" points where everytime
+        * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+        * point, we have to divide by one less.
+        */
+       
+       device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+       thisraid = &raid[device];
+       if (thisraid->stride==0)
+               thisraid->stride=1;
+
+       /* Partitions need adding of the start sector of the partition to the requested sector */
+       
+       rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+       /* Woops we need to split the request to avoid crossing a stride barrier */
+       if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+               return -1;
+       }
+                       
+       rsect_left = rsect;
+       
+       for (i=0;i<8;i++) {
+               if (thisraid->cutoff_disks[i]==0)
+                       break;
+               if (rsect > thisraid->cutoff[i]) {
+                       /* we're in the wrong area so far */
+                       rsect_left -= thisraid->cutoff[i];
+                       rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+               } else {
+                       block = rsect_left / thisraid->stride;
+                       disk = block % thisraid->cutoff_disks[i];
+                       block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+                       rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+                       break;
+               }
+       }
+       
+       for (i=0;i<8;i++) {
+               if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+                       real_disk = i;
+                       break;
+               }
+               if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+                       disk--;
+               }
+               
+       }
+       disk = real_disk;
+       
+       /* All but the first disk have a 10 sector offset */
+       if (i>0)
+               rsect+=10;
+               
+       
+       /*
+        * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+        * is the only IO operation happening on this bh.
+        */
+        
+       bh->b_rdev = thisraid->disk[disk].device;
+       bh->b_rsector = rsect;
+
+       /*
+        * Let the main block layer submit the IO and resolve recursion:
+        */
+       return 1;
+}
+
+
+#include "hptraid.h"
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+       int ret = -EINVAL;
+       struct buffer_head *bh = NULL;
+       kdev_t dev = MKDEV(major,minor);
+       
+       if (blksize_size[major]==NULL)   /* device doesn't exist */
+               return -EINVAL;
+       
+
+       /* Superblock is at 4096+412 bytes */
+       set_blocksize (dev, 4096);
+       bh = bread (dev, 1, 4096);
+
+       
+       if (bh) {
+               memcpy (buffer, bh->b_data, bufsize);
+       } else {
+               printk(KERN_ERR "hptraid: Error reading superblock.\n");
+               goto abort;
+       }
+       ret = 0;
+abort:
+       if (bh)
+               brelse (bh);
+       return ret;
+}
+
+static unsigned long maxsectors (int major,int minor)
+{
+       unsigned long lba = 0;
+       kdev_t dev;
+       ide_drive_t *ideinfo;
+       
+       dev = MKDEV(major,minor);
+       ideinfo = get_info_ptr (dev);
+       if (ideinfo==NULL)
+               return 0;
+       
+       
+       /* first sector of the last cluster */
+       if (ideinfo->head==0) 
+               return 0;
+       if (ideinfo->sect==0)
+               return 0;
+       lba = (ideinfo->capacity);
+
+       return lba;
+}
+
+static void __init probedisk(int major, int minor,int device)
+{
+       int i;
+        struct highpoint_raid_conf *prom;
+       static unsigned char block[4096];
+       
+       if (maxsectors(major,minor)==0)
+               return;
+       
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+               return;
+                                                                                                                 
+        prom = (struct highpoint_raid_conf*)&block[512];
+                
+        if (prom->magic!=  0x5a7816f0)
+               return;
+        if (prom->type) {
+               printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
+               return;
+        }
+
+       i = prom->disk_number;
+       if (i<0)
+               return;
+       if (i>8) 
+               return;
+
+       raid[device].disk[i].bdev = bdget(MKDEV(major,minor));
+        if (raid[device].disk[i].bdev != NULL) {
+               int j=0;
+               struct gendisk *gd;
+               /* This is supposed to prevent others from stealing our underlying disks */
+               blkdev_get(raid[device].disk[i].bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW);
+               /* now blank the /proc/partitions table for the wrong partition table,
+                  so that scripts don't accidentally mount it and crash the kernel */
+                /* XXX: the 0 is an utter hack  --hch */
+               gd=get_gendisk(MKDEV(major, 0));
+               if (gd!=NULL) {
+                       for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
+                               gd->part[j].nr_sects=0;                                 
+                       put_gendisk(gd);
+               }
+        }
+       raid[device].disk[i].device = MKDEV(major,minor);
+       raid[device].disk[i].sectors = maxsectors(major,minor);
+       raid[device].stride = (1<<prom->raid0_shift);
+       raid[device].disks = prom->raid_disks;
+       raid[device].sectors = prom->total_secs;
+                       
+}
+
+static void __init fill_cutoff(int device)
+{
+       int i,j;
+       unsigned long smallest;
+       unsigned long bar;
+       int count;
+       
+       bar = 0;
+       for (i=0;i<8;i++) {
+               smallest = ~0;
+               for (j=0;j<8;j++) 
+                       if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+                               smallest = raid[device].disk[j].sectors;
+               count = 0;
+               for (j=0;j<8;j++) 
+                       if (raid[device].disk[j].sectors >= smallest)
+                               count++;
+               
+               smallest = smallest * count;            
+               bar = smallest;
+               raid[device].cutoff[i] = smallest;
+               raid[device].cutoff_disks[i] = count;
+               
+       }
+}
+
+
+static __init int hptraid_init_one(int device)
+{
+       int i,count;
+
+       probedisk(IDE0_MAJOR,  0, device);
+       probedisk(IDE0_MAJOR, 64, device);
+       probedisk(IDE1_MAJOR,  0, device);
+       probedisk(IDE1_MAJOR, 64, device);
+       probedisk(IDE2_MAJOR,  0, device);
+       probedisk(IDE2_MAJOR, 64, device);
+       probedisk(IDE3_MAJOR,  0, device);
+       probedisk(IDE3_MAJOR, 64, device);
+                                                                       
+       fill_cutoff(device);
+       
+       /* Initialize the gendisk structure */
+       
+       ataraid_register_disk(device,raid[device].sectors);
+
+       count=0;
+       printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
+               
+       for (i=0;i<8;i++) {
+               if (raid[device].disk[i].device!=0) {
+                       printk(KERN_INFO "Drive %i is %li Mb \n",
+                               i,raid[device].disk[i].sectors/2048);
+                       count++;
+               }
+       }
+       if (count) {
+               printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+               return 0;
+       } else {
+               printk(KERN_INFO "No raid array found\n");
+               return -ENODEV;
+       }
+       
+}
+
+static __init int hptraid_init(void)
+{
+       int retval,device;
+       
+       device=ataraid_get_device(&hptraid_ops);
+       if (device<0)
+               return -ENODEV;
+       retval = hptraid_init_one(device);
+       if (retval)
+               ataraid_release_device(device);
+       return retval;
+}
+
+static void __exit hptraid_exit (void)
+{
+       int i,device;
+       for (device = 0; device<16; device++) {
+               for (i=0;i<8;i++) 
+                       if (raid[device].disk[i].bdev) {
+                               blkdev_put(raid[device].disk[i].bdev, BDEV_RAW);
+                               bdput(raid[device].disk[i].bdev);
+                               raid[device].disk[i].bdev = NULL;
+                       }       
+               if (raid[device].sectors)
+                       ataraid_release_device(device);
+       }
+}
+
+static int hptraid_open(struct inode * inode, struct file * filp) 
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+static int hptraid_release(struct inode * inode, struct file * filp)
+{      
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+module_init(hptraid_init);
+module_exit(hptraid_exit);
diff --git a/drivers/ide/hptraid.h b/drivers/ide/hptraid.h
new file mode 100644 (file)
index 0000000..757e7b8
--- /dev/null
@@ -0,0 +1,49 @@
+
+struct highpoint_raid_conf
+{
+       int8_t  filler1[32];
+       u_int32_t       magic;
+#define HPT_MAGIC_OK   0x5a7816f0
+#define HPT_MAGIC_BAD  0x5a7816fd  
+
+       u_int32_t       magic_0;
+       u_int32_t       magic_1;
+       u_int32_t       order;  
+#define HPT_O_MIRROR   0x01  
+#define HPT_O_STRIPE   0x02
+#define HPT_O_OK       0x04
+
+       u_int8_t        raid_disks;
+       u_int8_t        raid0_shift; 
+       u_int8_t        type;
+#define HPT_T_RAID_0   0x00 
+#define HPT_T_RAID_1   0x01
+#define HPT_T_RAID_01_RAID_0   0x02
+#define HPT_T_SPAN             0x03
+#define HPT_T_RAID_3           0x04   
+#define HPT_T_RAID_5           0x05
+#define HPT_T_SINGLEDISK       0x06
+#define HPT_T_RAID_01_RAID_1   0x07
+
+       u_int8_t        disk_number;
+       u_int32_t       total_secs; 
+       u_int32_t       disk_mode;  
+       u_int32_t       boot_mode;
+       u_int8_t        boot_disk; 
+       u_int8_t        boot_protect;
+       u_int8_t        error_log_entries;
+       u_int8_t        error_log_index;  
+       struct
+       {
+               u_int32_t       timestamp;
+               u_int8_t        reason;   
+#define HPT_R_REMOVED          0xfe      
+#define HPT_R_BROKEN           0xff      
+
+               u_int8_t        disk;
+               u_int8_t        status;
+               u_int8_t        sectors;
+               u_int32_t       lba;
+       } errorlog[32];
+       u_int8_t        filler[60];
+};
diff --git a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c
new file mode 100644 (file)
index 0000000..b12fb0b
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors:    Arjan van de Ven <arjanv@redhat.com>
+               
+   
+
+
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int pdcraid_open(struct inode * inode, struct file * filp);
+static int pdcraid_release(struct inode * inode, struct file * filp);
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int pdcraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+
+struct pdcdisk {
+       kdev_t  device;
+       unsigned long sectors;
+       struct block_device *bdev;
+};
+
+struct pdcraid {
+       unsigned int stride;
+       unsigned int disks;
+       unsigned long sectors;
+       struct geom geom;
+       
+       struct pdcdisk disk[8];
+       
+       unsigned long cutoff[8];
+       unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations pdcraid_ops = {
+        open:                   pdcraid_open,
+       release:                pdcraid_release,
+       ioctl:                  pdcraid_ioctl,
+       make_request:           pdcraid_make_request
+};
+
+static struct pdcraid raid[16];
+
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor;
+       unsigned long sectors;
+
+       if (!inode || !inode->i_rdev)   
+               return -EINVAL;
+
+       minor = MINOR(inode->i_rdev)>>SHIFT;
+       
+       switch (cmd) {
+
+               case BLKGETSIZE:   /* Return device size */
+                       if (!arg)  return -EINVAL;
+                       sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+                       if (MINOR(inode->i_rdev)&15)
+                               return put_user(sectors, (long *) arg);
+                       return put_user(raid[minor].sectors , (long *) arg);
+                       break;
+                       
+
+               case HDIO_GETGEO:
+               {
+                       struct hd_geometry *loc = (struct hd_geometry *) arg;
+                       unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+                       
+                       if (!loc) return -EINVAL;
+                       if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+                       if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+                       if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+                       if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+                               (unsigned long *) &loc->start)) return -EFAULT;
+                       return 0;
+               }
+
+               case HDIO_GETGEO_BIG:
+               {
+                       struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+                       if (!loc) return -EINVAL;
+                       if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+                       if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+                       if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+                       if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+                               (unsigned long *) &loc->start)) return -EFAULT;
+                       return 0;
+               }
+
+                       
+               case BLKROSET:
+               case BLKROGET:
+               case BLKSSZGET:
+                       return blk_ioctl(inode->i_rdev, cmd, arg);
+
+               default:
+                       return -EINVAL;
+       };
+
+       return 0;
+}
+
+
+static int pdcraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+       unsigned long rsect;
+       unsigned long rsect_left,rsect_accum = 0;
+       unsigned long block;
+       unsigned int disk=0,real_disk=0;
+       int i;
+       int device;
+       struct pdcraid *thisraid;
+
+       rsect = bh->b_rsector;
+       
+       /* Ok. We need to modify this sector number to a new disk + new sector number. 
+        * If there are disks of different sizes, this gets tricky. 
+        * Example with 3 disks (1Gb, 4Gb and 5 GB):
+        * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+        * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+        * and the last 1Gb is disk 3 only.
+        *
+        * the way this is solved is like this: We have a list of "cutoff" points where everytime
+        * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+        * point, we have to divide by one less.
+        */
+       
+       device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+       thisraid = &raid[device];
+       if (thisraid->stride==0)
+               thisraid->stride=1;
+
+       /* Partitions need adding of the start sector of the partition to the requested sector */
+       
+       rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+       /* Woops we need to split the request to avoid crossing a stride barrier */
+       if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+               return -1;  
+       }
+       
+       rsect_left = rsect;
+       
+       for (i=0;i<8;i++) {
+               if (thisraid->cutoff_disks[i]==0)
+                       break;
+               if (rsect > thisraid->cutoff[i]) {
+                       /* we're in the wrong area so far */
+                       rsect_left -= thisraid->cutoff[i];
+                       rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+               } else {
+                       block = rsect_left / thisraid->stride;
+                       disk = block % thisraid->cutoff_disks[i];
+                       block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+                       rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+                       break;
+               }
+       }
+       
+       for (i=0;i<8;i++) {
+               if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+                       real_disk = i;
+                       break;
+               }
+               if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+                       disk--;
+               }
+               
+       }
+       disk = real_disk;
+               
+       
+       /*
+        * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+        * is the only IO operation happening on this bh.
+        */
+       bh->b_rdev = thisraid->disk[disk].device;
+       bh->b_rsector = rsect;
+
+       /*
+        * Let the main block layer submit the IO and resolve recursion:
+        */
+       return 1;
+}
+
+
+#include "pdcraid.h"
+
+static unsigned long calc_pdcblock_offset (int major,int minor)
+{
+       unsigned long lba = 0;
+       kdev_t dev;
+       ide_drive_t *ideinfo;
+       
+       dev = MKDEV(major,minor);
+       ideinfo = get_info_ptr (dev);
+       if (ideinfo==NULL)
+               return 0;
+       
+       
+       /* first sector of the last cluster */
+       if (ideinfo->head==0) 
+               return 0;
+       if (ideinfo->sect==0)
+               return 0;
+       lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+       lba = lba * (ideinfo->head*ideinfo->sect);
+       lba = lba - ideinfo->sect;
+
+       return lba;
+}
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+       int ret = -EINVAL;
+       struct buffer_head *bh = NULL;
+       kdev_t dev = MKDEV(major,minor);
+       unsigned long sb_offset;
+
+       if (blksize_size[major]==NULL)   /* device doesn't exist */
+               return -EINVAL;
+                       
+       
+       /*
+        * Calculate the position of the superblock,
+        * it's at first sector of the last cylinder
+        */
+       sb_offset = calc_pdcblock_offset(major,minor)/8;
+       /* The /8 transforms sectors into 4Kb blocks */
+
+       if (sb_offset==0)
+               return -1;      
+       
+       set_blocksize (dev, 4096);
+
+       bh = bread (dev, sb_offset, 4096);
+       
+       if (bh) {
+               memcpy (buffer, bh->b_data, bufsize);
+       } else {
+               printk(KERN_ERR "pdcraid: Error reading superblock.\n");
+               goto abort;
+       }
+       ret = 0;
+abort:
+       if (bh)
+               brelse (bh);
+       return ret;
+}
+
+static unsigned int calc_sb_csum (unsigned int* ptr)
+{      
+       unsigned int sum;
+       int count;
+       
+       sum = 0;
+       for (count=0;count<511;count++)
+               sum += *ptr++;
+       
+       return sum;
+}
+
+static void __init probedisk(int major, int minor,int device)
+{
+       int i;
+        struct promise_raid_conf *prom;
+       static unsigned char block[4096];
+       
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+               return;
+                                                                                                                 
+        prom = (struct promise_raid_conf*)&block[512];
+
+        /* the checksums must match */
+       if (prom->checksum != calc_sb_csum((unsigned int*)prom))
+               return;
+       if (prom->raid.type!=0x00) /* Only raid 0 is supported right now */
+               return;
+       
+
+       /* This looks evil. But basically, we have to search for our adapternumber
+          in the arraydefinition, both of which are in the superblock */       
+        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
+               if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
+                    (prom->raid.disk[i].device == prom->raid.device) ) {
+                       raid[device].disk[i].bdev = bdget(MKDEV(major,minor));
+                       if (raid[device].disk[i].bdev != NULL) {
+                               struct gendisk *gd;
+                               int j;
+                               /* This is supposed to prevent others from stealing our underlying disks */
+                               blkdev_get(raid[device].disk[i].bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW);
+                               gd=get_gendisk(major);
+                               if (gd!=NULL) {
+                                       for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
+                                               gd->part[j].nr_sects=0;                                 
+                                       put_gendisk(gd);
+                               }
+                       }
+                       raid[device].disk[i].device = MKDEV(major,minor);
+                       raid[device].disk[i].sectors = prom->raid.disk_secs;
+                       raid[device].stride = (1<<prom->raid.raid0_shift);
+                       raid[device].disks = prom->raid.total_disks;
+                       raid[device].sectors = prom->raid.total_secs;
+                       raid[device].geom.heads = prom->raid.heads+1;
+                       raid[device].geom.sectors = prom->raid.sectors;
+                       raid[device].geom.cylinders = prom->raid.cylinders+1;
+                       
+                    }
+        }
+                      
+}
+
+static void __init fill_cutoff(int device)
+{
+       int i,j;
+       unsigned long smallest;
+       unsigned long bar;
+       int count;
+       
+       bar = 0;
+       for (i=0;i<8;i++) {
+               smallest = ~0;
+               for (j=0;j<8;j++) 
+                       if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+                               smallest = raid[device].disk[j].sectors;
+               count = 0;
+               for (j=0;j<8;j++) 
+                       if (raid[device].disk[j].sectors >= smallest)
+                               count++;
+                               
+               smallest = smallest * count;
+               bar = smallest;
+               raid[device].cutoff[i] = smallest;
+               raid[device].cutoff_disks[i] = count;
+       }
+}
+                          
+static __init int pdcraid_init_one(int device)
+{
+       int i,count;
+
+       probedisk(IDE0_MAJOR,  0, device);
+       probedisk(IDE0_MAJOR, 64, device);
+       probedisk(IDE1_MAJOR,  0, device);
+       probedisk(IDE1_MAJOR, 64, device);
+       probedisk(IDE2_MAJOR,  0, device);
+       probedisk(IDE2_MAJOR, 64, device);
+       probedisk(IDE3_MAJOR,  0, device);
+       probedisk(IDE3_MAJOR, 64, device);
+       
+       fill_cutoff(device);
+       
+       /* Initialize the gendisk structure */
+       
+       ataraid_register_disk(device,raid[device].sectors);        
+               
+       count=0;
+       printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.02\n");
+       
+       for (i=0;i<8;i++) {
+               if (raid[device].disk[i].device!=0) {
+                       printk(KERN_INFO "Drive %i is %li Mb \n",
+                               i,raid[device].disk[i].sectors/2048);
+                       count++;
+               }
+       }
+       if (count) {
+               printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+               return 0;
+       } else {
+               printk(KERN_INFO "No raid array found\n");
+               return -ENODEV;
+       }
+}
+
+static __init int pdcraid_init(void)
+{
+       int retval,device;
+       
+       device=ataraid_get_device(&pdcraid_ops);
+       if (device<0)
+               return -ENODEV;
+       retval = pdcraid_init_one(device);
+       if (retval)
+               ataraid_release_device(device);
+       return retval;
+}
+
+static void __exit pdcraid_exit (void)
+{
+       int i,device;
+       for (device = 0; device<16; device++) {
+               for (i=0;i<8;i++) 
+                       if (raid[device].disk[i].bdev) {
+                               blkdev_put(raid[device].disk[i].bdev, BDEV_RAW);
+                               bdput(raid[device].disk[i].bdev);
+                               raid[device].disk[i].bdev = NULL;
+
+                       }       
+               if (raid[device].sectors)
+                       ataraid_release_device(device);
+       }
+}
+
+static int pdcraid_open(struct inode * inode, struct file * filp) 
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+static int pdcraid_release(struct inode * inode, struct file * filp)
+{      
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+module_init(pdcraid_init);
+module_exit(pdcraid_exit);
diff --git a/drivers/ide/pdcraid.h b/drivers/ide/pdcraid.h
new file mode 100644 (file)
index 0000000..e6e3694
--- /dev/null
@@ -0,0 +1,47 @@
+struct promise_raid_conf {
+    char                promise_id[24];
+
+    u32             dummy_0;
+    u32             magic_0;
+    u32             dummy_1;
+    u32             magic_1;
+    u16             dummy_2;
+    u8              filler1[470];
+    struct {
+        u32 flags;                          /* 0x200 */
+        u8          dummy_0;
+        u8          disk_number;
+        u8          channel;
+        u8          device;
+        u32         magic_0;
+        u32         dummy_1;
+        u32         dummy_2;                /* 0x210 */
+        u32         disk_secs;
+        u32         dummy_3;
+        u16         dummy_4;
+        u8          status;
+        u8          type;
+        u8        total_disks;            /* 0x220 */
+        u8        raid0_shift;
+        u8        raid0_disks;
+        u8        array_number;
+        u32       total_secs;
+        u16       cylinders;
+        u8        heads;
+        u8        sectors;
+        u32         magic_1;
+        u32         dummy_5;                /* 0x230 */
+        struct {
+            u16     dummy_0;
+            u8      channel;
+            u8      device;
+            u32     magic_0;
+            u32     disk_number;
+        } disk[8];
+    } raid;
+    u32             filler2[346];
+    u32            checksum;
+};
+
+#define PR_MAGIC        "Promise Technology, Inc."
+
index fffc893b7774dace9a0f5ec3e17b49f511f0b42b..37ac83b29244520b74e84f7ff7c4a0f079cd32f0 100644 (file)
@@ -352,7 +352,7 @@ static void nodemgr_node_probe(void *data)
 {
        struct hpsb_host *host = (struct hpsb_host *)data;
         struct selfid *sid = (struct selfid *)host->topology_map;
-       struct list_head *lh;
+       struct list_head *lh,*spare;
        struct node_entry *ne;
         int nodecount = host->node_count;
         nodeid_t nodeid = LOCAL_BUS;
@@ -442,7 +442,7 @@ set_options:
        /* Now check to see if we have any nodes that aren't referenced
         * any longer.  */
         write_lock_irqsave(&node_lock, flags);
-       list_for_each(lh, &node_list) {
+       list_for_each_safe(lh, spare, &node_list) {
                ne = list_entry(lh, struct node_entry, list);
 
                /* Only checking this host */
index 6172d6121bbaabfffcef564339f598b5599cf969..e8f31fab6da6ddc5ac2a971b6e7e80689aa59497 100644 (file)
@@ -48,6 +48,8 @@ static int sparc_l1_a_state = 0;
 extern void batten_down_hatches(void);
 #endif
 
+static int jp_kbd_109 = 1;     /* Yes, .jp is the default. See 51142. */
+
 static unsigned short x86_keycodes[256] =
        { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
         16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -220,6 +222,15 @@ static int __init keybdev_init(void)
 {
        input_register_handler(&keybdev_handler);
        kbd_ledfunc = keybdev_ledfunc;
+
+       if (jp_kbd_109) {
+               x86_keycodes[0xb5] = 0x73;      /* backslash, underscore */
+               x86_keycodes[0xb6] = 0x70;
+               x86_keycodes[0xb7] = 0x7d;      /* Yen, pipe */
+               x86_keycodes[0xb8] = 0x79;
+               x86_keycodes[0xb9] = 0x7b;
+       }
+
        return 0;
 }
 
@@ -234,3 +245,4 @@ module_exit(keybdev_exit);
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input driver to keyboard driver binding");
+MODULE_PARM(jp_kbd_109, "i");
index 1b6ccc646fa0e1a75d0d9fb5952046f1d612321c..c6a0e48f22cd9f9d276ef2f13c966eebb3fab7f1 100644 (file)
@@ -13,6 +13,7 @@
  * - /proc/adb to list the devices and infos
  * - more /dev/adb to allow userland to receive the
  *   flow of auto-polling datas from a given device.
+ * - move bus probe to a kernel thread
  */
 
 #include <linux/config.h>
@@ -32,6 +33,7 @@
 #include <linux/notifier.h>
 #include <linux/wait.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
@@ -74,6 +76,11 @@ struct adb_driver *adb_controller;
 struct notifier_block *adb_client_list = NULL;
 static int adb_got_sleep = 0;
 static int adb_inited = 0;
+static pid_t adb_probe_task_pid;
+static int adb_probe_task_flag;
+static wait_queue_head_t adb_probe_task_wq;
+static int sleepy_trackpad;
+int __adb_probe_sync;
 
 #ifdef CONFIG_PMAC_PBOOK
 static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
@@ -84,6 +91,9 @@ static struct pmu_sleep_notifier adb_sleep_notifier = {
 #endif
 
 static int adb_scan_bus(void);
+static int do_adb_reset_bus(void);
+static void adbdev_init(void);
+
 
 static struct adb_handler {
        void (*handler)(unsigned char *, int, struct pt_regs *, int);
@@ -104,6 +114,17 @@ static void printADBreply(struct adb_request *req)
 }
 #endif
 
+
+static __inline__ void adb_wait_ms(unsigned int ms)
+{
+       if (current->pid && adb_probe_task_pid &&
+         adb_probe_task_pid == current->pid) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(1 + ms * HZ / 1000);
+       } else
+               mdelay(ms);
+}
+
 static int adb_scan_bus(void)
 {
        int i, highFree=0, noMovement;
@@ -201,6 +222,64 @@ static int adb_scan_bus(void)
        return devmask;
 }
 
+/*
+ * This kernel task handles ADB probing. It dies once probing is
+ * completed.
+ */
+static int
+adb_probe_task(void *x)
+{
+       strcpy(current->comm, "kadbprobe");
+       
+       spin_lock_irq(&current->sigmask_lock);
+       sigfillset(&current->blocked);
+       flush_signals(current);
+       spin_unlock_irq(&current->sigmask_lock);
+
+       printk(KERN_INFO "adb: starting probe task...\n");
+       do_adb_reset_bus();
+       printk(KERN_INFO "adb: finished probe task...\n");
+       
+       adb_probe_task_pid = 0;
+       clear_bit(0, &adb_probe_task_flag);
+       return 0;
+}
+
+static void
+__adb_probe_task(void *data)
+{
+       adb_probe_task_pid = kernel_thread(adb_probe_task, NULL,
+               SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+}
+
+int
+adb_reset_bus(void)
+{
+       static struct tq_struct tqs = {
+               routine:        __adb_probe_task,
+       };
+
+       if (__adb_probe_sync) {
+               do_adb_reset_bus();
+               return 0;
+       }
+               
+       /* We need to get a lock on the probe thread */
+       while (test_and_set_bit(0, &adb_probe_task_flag))
+               schedule();
+
+       /* Just wait for PID to be 0 just in case (possible race) */
+       while (adb_probe_task_pid != 0)
+               schedule();
+
+       /* Create probe thread as a child of keventd */
+       if (current_is_keventd())
+               __adb_probe_task(NULL);
+       else
+               schedule_task(&tqs);
+       return 0;
+}
+
 int __init adb_init(void)
 {
        struct adb_driver *driver;
@@ -231,11 +310,16 @@ int __init adb_init(void)
        }
        if ((adb_controller == NULL) || adb_controller->init()) {
                printk(KERN_WARNING "Warning: no ADB interface detected\n");
+               adb_controller = NULL;
        } else {
 #ifdef CONFIG_PMAC_PBOOK
                pmu_register_sleep_notifier(&adb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
-
+               if (machine_is_compatible("AAPL,PowerBook1998") ||
+                       machine_is_compatible("PowerBook1,1"))
+                       sleepy_trackpad = 1;
+               init_waitqueue_head(&adb_probe_task_wq);
+               adbdev_init();
                adb_reset_bus();
        }
        return 0;
@@ -255,6 +339,12 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
        switch (when) {
        case PBOOK_SLEEP_REQUEST:
                adb_got_sleep = 1;
+               /* We need to get a lock on the probe thread */
+               while (test_and_set_bit(0, &adb_probe_task_flag))
+                       schedule();
+               /* Just wait for PID to be 0 just in case (possible race) */
+               while (adb_probe_task_pid != 0)
+                       schedule();
                if (adb_controller->autopoll)
                        adb_controller->autopoll(0);
                ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
@@ -264,6 +354,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
        case PBOOK_SLEEP_REJECT:
                if (adb_got_sleep) {
                        adb_got_sleep = 0;
+                       clear_bit(0, &adb_probe_task_flag);
                        adb_reset_bus();
                }
                break;
@@ -271,16 +362,17 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
        case PBOOK_SLEEP_NOW:
                break;
        case PBOOK_WAKE:
-               adb_reset_bus();
                adb_got_sleep = 0;
+               clear_bit(0, &adb_probe_task_flag);
+               adb_reset_bus();
                break;
        }
        return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
-int
-adb_reset_bus(void)
+static int
+do_adb_reset_bus(void)
 {
        int ret, nret, devs;
        unsigned long flags;
@@ -298,16 +390,27 @@ adb_reset_bus(void)
                return -EBUSY;
        }
 
+       if (sleepy_trackpad) {
+               /* Let the trackpad settle down */
+               adb_wait_ms(500);
+       }
+       
        save_flags(flags);
        cli();
        memset(adb_handler, 0, sizeof(adb_handler));
        restore_flags(flags);
-       
+
+       /* That one is still a bit synchronous, oh well... */
        if (adb_controller->reset_bus)
                ret = adb_controller->reset_bus();
        else
                ret = 0;
 
+       if (sleepy_trackpad) {
+               /* Let the trackpad settle down */
+               adb_wait_ms(1500);
+       }
+
        if (!ret) {
                devs = adb_scan_bus();
                if (adb_controller->autopoll)
@@ -329,24 +432,40 @@ adb_poll(void)
        adb_controller->poll();
 }
 
+static void
+adb_probe_wakeup(struct adb_request *req)
+{
+       wake_up(&adb_probe_task_wq);
+}
+
+static struct adb_request adb_sreq;
+static int adb_sreq_lock; // Use semaphore ! */ 
 
 int
 adb_request(struct adb_request *req, void (*done)(struct adb_request *),
            int flags, int nbytes, ...)
 {
        va_list list;
-       int i;
-       struct adb_request sreq;
+       int i, use_sreq;
+       int rc;
 
        if ((adb_controller == NULL) || (adb_controller->send_request == NULL))
                return -ENXIO;
        if (nbytes < 1)
                return -EINVAL;
+       if (req == NULL && (flags & ADBREQ_NOSEND))
+               return -EINVAL;
        
        if (req == NULL) {
-               req = &sreq;
+               if (test_and_set_bit(0,&adb_sreq_lock)) {
+                       printk("adb.c: Warning: contention on static request !\n");
+                       return -EPERM;
+               }
+               req = &adb_sreq;
                flags |= ADBREQ_SYNC;
-       }
+               use_sreq = 1;
+       } else
+               use_sreq = 0;
        req->nbytes = nbytes+1;
        req->done = done;
        req->reply_expected = flags & ADBREQ_REPLY;
@@ -359,7 +478,36 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
        if (flags & ADBREQ_NOSEND)
                return 0;
 
-       return adb_controller->send_request(req, flags & ADBREQ_SYNC);
+       /* Synchronous requests send from the probe thread cause it to
+        * block. Beware that the "done" callback will be overriden !
+        */
+       if ((flags & ADBREQ_SYNC) &&
+           (current->pid && adb_probe_task_pid &&
+           adb_probe_task_pid == current->pid)) {
+               DECLARE_WAITQUEUE(wait, current);
+               req->done = adb_probe_wakeup;
+               add_wait_queue(&adb_probe_task_wq, &wait);
+               rc = adb_controller->send_request(req, 0);
+               if (rc || req->complete)
+                       goto bail;
+               for (;;) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       if (req->complete)
+                               break;
+                       schedule();
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&adb_probe_task_wq, &wait);
+               rc = 0;
+               goto bail;
+       }
+
+       rc = adb_controller->send_request(req, flags & ADBREQ_SYNC);
+bail:
+       if (use_sreq)
+               clear_bit(0, &adb_sreq_lock);
+
+       return rc;
 }
 
  /* Ultimately this should return the number of devices with
@@ -463,8 +611,6 @@ adb_get_infos(int address, int *original_address, int *handler_id)
 
 #define ADB_MAJOR      56      /* major number for /dev/adb */
 
-extern void adbdev_init(void);
-
 struct adbdev_state {
        spinlock_t      lock;
        atomic_t        n_pending;
@@ -636,7 +782,7 @@ static ssize_t adb_write(struct file *file, const char *buf,
           the controller */
        if ((req->data[0] == ADB_PACKET)&&(count > 1)
                &&(req->data[1] == ADB_BUSRESET)) {
-               ret = adb_reset_bus();
+               ret = do_adb_reset_bus();
                atomic_dec(&state->n_pending);
                goto out;
        } else {        
@@ -667,17 +813,9 @@ static struct file_operations adb_fops = {
        release:        adb_release,
 };
 
-void adbdev_init()
+static void
+adbdev_init(void)
 {
-#ifdef CONFIG_PPC
-       if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-               return;
-#endif
-#ifdef CONFIG_MAC
-       if (!MACH_IS_MAC)
-               return;
-#endif
-
        if (devfs_register_chrdev(ADB_MAJOR, "adb", &adb_fops))
                printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
        else
index bc1c8a7b83a8d8285241d66dbe84cd8133ac9466..11a5098d35675b3f880ce64c976bf077ec9fa9b5 100644 (file)
@@ -690,12 +690,13 @@ init_trackpad(int id)
        printk(" (trackpad)");
 
        adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-       ADB_READREG(id,1));
+               ADB_READREG(id,1));
        if (req.reply_len < 8)
            printk("bad length for reg. 1\n");
        else
        {
            memcpy(r1_buffer, &req.reply[1], 8);
+
            adb_request(&req, NULL, ADBREQ_SYNC, 9,
                ADB_WRITEREG(id,1),
                    r1_buffer[0],
@@ -704,7 +705,7 @@ init_trackpad(int id)
                    r1_buffer[3],
                    r1_buffer[4],
                    r1_buffer[5],
-                   0x0d, /*r1_buffer[6],*/
+                   0x0d,
                    r1_buffer[7]);
 
             adb_request(&req, NULL, ADBREQ_SYNC, 9,
@@ -717,7 +718,7 @@ init_trackpad(int id)
                    0x8a,
                    0x1b,
                    0x50);
-           
+
            adb_request(&req, NULL, ADBREQ_SYNC, 9,
                ADB_WRITEREG(id,1),
                    r1_buffer[0],
@@ -728,6 +729,9 @@ init_trackpad(int id)
                    r1_buffer[5],
                    0x03, /*r1_buffer[6],*/
                    r1_buffer[7]);
+
+           /* Without this flush, the trackpad may be locked up */         
+           adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
         }
 }
 
index 516adf79c2b91779a762db5fdf91416f695b5838..7b4075edf13d4362127be926e81b9e4913662e35 100644 (file)
@@ -908,6 +908,9 @@ init_trackpad(int id)
                    r1_buffer[5],
                    0x03, /*r1_buffer[6],*/
                    r1_buffer[7]);
+
+           /* Without this flush, the trackpad may be locked up */         
+           adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
         }
 }
 
index 68b0db082a477d40695f17e39def34d67a93d177..4dedd9062a26bd9fe22e4e1b48bcc86c08fcf259 100644 (file)
@@ -13,19 +13,27 @@ if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
    int '    Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
 fi
 
-dep_tristate '  Sun Microsystems userflash support' CONFIG_MTD_SUN_UFLASH $CONFIG_SPARC64
-dep_tristate '  CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
+if [ "$CONFIG_SPARC" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
+   dep_tristate '  Sun Microsystems userflash support' CONFIG_MTD_SUN_UFLASH $CONFIG_SPARC64
+fi
+if [ "$CONFIG_ARM" = "y" ]; then
+   dep_tristate '  CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI
+fi
 dep_tristate '  CFI Flash device mapped on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
 dep_tristate '  CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI 
-dep_tristate '  CFI Flash device mapped on AMD SC520 CDP' CONFIG_MTD_SC520CDP $CONFIG_MTD_CFI
-dep_tristate '  CFI Flash device mapped on AMD NetSc520'  CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
+if [ "$CONFIG_X86" = "y"  ]; then
+   dep_tristate '  CFI Flash device mapped on AMD SC520 CDP' CONFIG_MTD_SC520CDP $CONFIG_MTD_CFI
+   dep_tristate '  CFI Flash device mapped on AMD NetSc520'  CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
+fi
 dep_tristate '  CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
 dep_tristate '  CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS
+if [ "$CONFIG_ARM" = "y" ]; then
 dep_tristate '  CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
    dep_bool '    Support for RedBoot partition tables on SA11x0' CONFIG_MTD_SA1100_REDBOOT_PARTITIONS $CONFIG_MTD_SA1100 $CONFIG_MTD_REDBOOT_PARTS
    dep_bool '    Support for Compaq bootldr partition tables on SA11x0' CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS $CONFIG_MTD_SA1100 $CONFIG_MTD_BOOTLDR_PARTS
-dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
-dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_XSCALE_IQ80310
+   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+   dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_XSCALE_IQ80310
+fi
 dep_tristate '  CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI_INTELSTD $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI_AMDSTD
 dep_tristate '  Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS 
 if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
index ac2b008eba1240fe42bcbc34f92e9b357f843efd..785893ed42ba62569f7d719cddafef4254f5417c 100644 (file)
@@ -8,8 +8,8 @@ comment 'NAND Flash Device Drivers'
 
 dep_tristate '  NAND Device Support' CONFIG_MTD_NAND $CONFIG_MTD
 if [ "$CONFIG_MTD_NAND" = "y" -o "$CONFIG_MTD_NAND" = "m" ]; then
-   bool '    Enable ECC correction algorithm'  CONFIG_MTD_NAND_ECC y
-   bool '    Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE y
+   bool '    Enable ECC correction algorithm'  CONFIG_MTD_NAND_ECC
+   bool '    Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE
 fi
 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then
    dep_tristate '  NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
index 3f1b1455af9db44bd8717e2f9129fbc06542523c..2c86a8037051c6ee96c42a924d82dcecee184dd1 100644 (file)
@@ -25,12 +25,13 @@ fi
 
 mainmenu_option next_comment
 comment 'Ethernet (10 or 100Mbit)'
-
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-   dep_bool '  ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
-   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
-      source drivers/acorn/net/Config.in
+   if [ "$CONFIG_ARM" = "y" ]; then  
+      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
    fi
    if [ "$CONFIG_PPC" = "y" ]; then
       tristate '  MACE (Power Mac ethernet) support' CONFIG_MACE
@@ -48,12 +49,18 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       tristate '  A2065 support' CONFIG_A2065
       tristate '  Hydra support' CONFIG_HYDRA
    fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+      dep_tristate '  Lasi ethernet' CONFIG_LASI_82596 $CONFIG_GSC_LASI
+   fi
    if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
       tristate '  MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
    fi
    if [ "$CONFIG_MIPS_GT96100" = "y" ]; then
       bool '  MIPS GT96100 Ethernet support' CONFIG_MIPS_GT96100ETH
    fi
+   if [ "$CONFIG_MIPS_AU1000" = "y" ]; then
+      bool '  MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET
+   fi
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
@@ -105,7 +112,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       dep_tristate '    NI6510 support' CONFIG_NI65 $CONFIG_ISA
    fi
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
-      dep_tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 $CONFIG_EXPERIMENTAL
+         dep_tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 $CONFIG_EXPERIMENTAL
    fi
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
       tristate '  DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
@@ -124,6 +131,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       fi
       tristate '    HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
       tristate '    HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
+      tristate '    LP486E on board Ethernet' CONFIG_LP486E
       tristate '    ICL EtherTeam 16i/32 support' CONFIG_ETH16I
       tristate '    NE2000/NE1000 support' CONFIG_NE2000
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
@@ -138,10 +146,10 @@ 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
-   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-      bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+     bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
    else
-      define_bool CONFIG_NET_PCI n
+     define_bool CONFIG_NET_PCI n
    fi
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
@@ -153,8 +161,10 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       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
-      dep_mbool '      New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL $CONFIG_TULIP
-      dep_mbool '      Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO $CONFIG_TULIP
+      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
@@ -182,7 +192,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
         dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
       fi
-      if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ORION" = "y" ]; then
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
       fi
    fi
@@ -194,6 +204,15 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
       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
+   if [ "$CONFIG_SGI_IP22" = "y" ]; then
+      bool '  SGI Seeq ethernet controller support' CONFIG_SGISEEQ
+   fi
+   if [ "$CONFIG_DECSTATION" = "y" ]; then
+      bool '  DEC LANCE ethernet controller support' CONFIG_DECLANCE
+   fi 
+   if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
+      tristate '  Baget AMD LANCE support' CONFIG_BAGETLANCE
+   fi
 fi
 
 endmenu
@@ -206,15 +225,22 @@ mainmenu_option next_comment
 comment 'Ethernet (1000 Mbit)'
 
 dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI
-dep_mbool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I $CONFIG_ACENIC
+if [ "$CONFIG_ACENIC" != "n" ]; then
+   bool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
+fi
 dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI
 dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
+dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 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
 
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+   dep_tristate 'iSeries Virtual Ethernet driver support' CONFIG_VETH $CONFIG_PPC_ISERIES
+fi
+
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
    if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
@@ -245,7 +271,9 @@ if [ ! "$CONFIG_PPP" = "n" ]; then
    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 $CONFIG_PPP
-   dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+   fi
 fi
 
 tristate 'SLIP (serial line) support' CONFIG_SLIP
index 83a3dc4dd39a341adf9d2b39b2c1e7575458f6f4..258a9da5ddfb6c3a35aefec86ded5774fab8d24e 100644 (file)
@@ -74,7 +74,9 @@ obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_DM9102) += dmfe.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
 obj-$(CONFIG_ACENIC) += acenic.o
+obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_NATSEMI) += natsemi.o
+obj-$(CONFIG_NS83820) += ns83820.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o
 
@@ -142,8 +144,6 @@ ifeq ($(CONFIG_SLIP_COMPRESSED),y)
 endif
 
 obj-$(CONFIG_STRIP) += strip.o
-obj-$(CONFIG_DE650) += de650.o 8390.o
-obj-$(CONFIG_3C589) += 3c589.o
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_BONDING) += bonding.o
 obj-$(CONFIG_DE600) += de600.o
@@ -180,8 +180,13 @@ obj-$(CONFIG_NI65) += ni65.o
 obj-$(CONFIG_ELPLUS) += 3c505.o
 obj-$(CONFIG_AC3200) += ac3200.o 8390.o
 obj-$(CONFIG_APRICOT) += 82596.o
+obj-$(CONFIG_LASI_82596) += lasi_82596.o
 obj-$(CONFIG_MVME16x_NET) += 82596.o
 obj-$(CONFIG_BVME6000_NET) += 82596.o
+
+# This is also a 82596 and should probably be merged
+obj-$(CONFIG_LP486E) += lp486e.o
+
 obj-$(CONFIG_ETH16I) += eth16i.o
 obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
@@ -189,6 +194,7 @@ obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
 obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
+obj-$(CONFIG_MIPS_AU1000_ENET) += au1000_eth.o
 obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_BAGETLANCE) += bagetlance.o
 obj-$(CONFIG_DECLANCE) += declance.o
index 92b55d045a8f3ff83a86ffdc71a096ec99a66c01..596a946661d4bb6361ed09299806315fe59f9eba 100644 (file)
@@ -59,6 +59,13 @@ static const char *awc_version =
 
 #include <linux/pci.h>
 
+static struct pci_device_id aironet4500_card_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_AIRONET, PCI_DEVICE_AIRONET_4800_1, PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_AIRONET, PCI_DEVICE_AIRONET_4800, PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_AIRONET, PCI_DEVICE_AIRONET_4500, PCI_ANY_ID, PCI_ANY_ID, },
+       { }                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, aironet4500_card_pci_tbl);
 
 static int reverse_probe;
 
@@ -168,6 +175,13 @@ static int awc_pci_init(struct net_device * dev, struct pci_dev *pdev,
                allocd_dev = 1;
        }
        dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL );
+        if (!dev->priv) {
+                if (allocd_dev) {
+                        unregister_netdev(dev);
+                        kfree(dev);
+                }
+                return -ENOMEM;
+        }       
        memset(dev->priv,0,sizeof(struct awc_private));
        if (!dev->priv) {
                printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n");
@@ -488,6 +502,14 @@ static void awc_pnp_release(void) {
 
 } 
 
+static struct isapnp_device_id id_table[] = {
+       {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+               ISAPNP_VENDOR('A','W','L'), ISAPNP_DEVICE(1), 0 },
+       {0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
 #endif //MODULE
 #endif /* CONFIG_AIRONET4500_PNP */
 
@@ -634,7 +656,7 @@ static void awc_isa_release(void) {
 
 #endif /* CONFIG_AIRONET4500_ISA */
 
-#ifdef  CONFIG_AIRONET4500_365 
+#ifdef  CONFIG_AIRONET4500_I365 
 
 #define port_range 0x40
 
@@ -954,7 +976,7 @@ failed:
 
 }
 
-#endif /* CONFIG_AIRONET4500_365 */
+#endif /* CONFIG_AIRONET4500_I365 */
 
 #ifdef MODULE        
 int init_module(void)
index 1166753106efcaf8612edf8dddec35fb7a058192..9a07d2f026651f27b315a2c0dc04ac5434cbc02e 100644 (file)
@@ -2564,7 +2564,6 @@ int awc_simple_bridge;
 #if LINUX_VERSION_CODE >= 0x20100
 
 MODULE_PARM(awc_debug,"i");
-MODULE_PARM(rx_queue_len,"i");
 MODULE_PARM(tx_rate,"i");
 MODULE_PARM(channel,"i");
 //MODULE_PARM(tx_full_rate,"i");
@@ -2600,7 +2599,6 @@ EXPORT_SYMBOL(awc_debug);
 EXPORT_SYMBOL(awc_private_init);
 EXPORT_SYMBOL(awc_tx_timeout);
 EXPORT_SYMBOL(awc_start_xmit);
-//EXPORT_SYMBOL(awc_rx);
 EXPORT_SYMBOL(awc_interrupt);
 EXPORT_SYMBOL(awc_get_stats);
 EXPORT_SYMBOL(awc_change_mtu);
@@ -2976,7 +2974,7 @@ int awc_private_init(struct net_device * dev){
        
        awc_reset(dev);
        
-       udelay(10000);
+       mdelay(10);
        
        AWC_LOCK_COMMAND_ISSUING(priv);
 
@@ -3072,31 +3070,7 @@ int awc_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        return retval;
 }
 
-inline int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
-
-//     struct awc_private *lp = (struct awc_private *)dev->priv;
-
-       DEBUG(3, "%s: in rx_packet \n",dev->name);
-
-       if (!rx_fid ){
-               DEBUG(3, "%s: not rx_buff in rx_packet \n",dev->name);
-               return -1;
-       };
-       if ( !rx_fid->skb){
-               DEBUG(3, "%s: not  rx_buff->skb in rx_packet \n",dev->name);
-               return -1;
-       };
-
-       
-       rx_fid->skb->protocol = eth_type_trans(rx_fid->skb,dev);
-       netif_rx(rx_fid->skb);
-        rx_fid = NULL;
-
-       return 0;
-}
-
-
- void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct net_device *dev = dev_id;
        struct awc_private *priv;
@@ -3115,8 +3089,6 @@ inline int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
        awc_interrupt_process(dev);
 
        spin_unlock_irqrestore(&priv->interrupt_spinlock, flags);         
-
-       return;
 }
 
 
index 60555bf262b25268b82c3f8dff5d87cf400a8144..56a951e1d72ad081550eb746e37bddb983e9ecc0 100644 (file)
@@ -59,7 +59,7 @@ struct awc_proc_private{
        char                            proc_name[10];
 };             
 static char awc_drive_info[AWC_STR_SIZE]="Zcom \n\0";
-static char awc_proc_buff[AWC_STR_SIZE]="\0";
+static char awc_proc_buff[AWC_STR_SIZE];
 static int  awc_int_buff;
 static struct awc_proc_private awc_proc_priv[MAX_AWCS]; 
 
@@ -403,7 +403,7 @@ ctl_table awc_root_table[] = {
         {0}
 };
 
-struct ctl_table_header * awc_driver_sysctl_header = NULL;
+struct ctl_table_header * awc_driver_sysctl_header;
 
 const char awc_procname[]= "awc5";
 
index 84d91cb4e6c37748bf43e8d83e9a1c26454f0a5b..bafad186bf3eae61f85c79f6e76e7731be2be56c 100644 (file)
@@ -76,6 +76,8 @@ struct bmac_data {
        struct net_device_stats stats;
        struct timer_list tx_timeout;
        int timeout_active;
+       int sleeping;
+       int opened;
        unsigned short hash_use_count[64];
        unsigned short hash_table_mask[4];
        struct net_device *next_bmac;
@@ -466,11 +468,15 @@ static int
 bmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
        struct bmac_data *bp;
-
+       unsigned long flags;
+       unsigned short config;
+       struct net_device* dev = bmac_devs;
+       int i;
+       
        if (bmac_devs == 0)
                return PBOOK_SLEEP_OK;
                
-       bp = (struct bmac_data *) bmac_devs->priv;
+       bp = (struct bmac_data *) dev->priv;
        
        switch (when) {
        case PBOOK_SLEEP_REQUEST:
@@ -478,21 +484,57 @@ bmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
        case PBOOK_SLEEP_REJECT:
                break;
        case PBOOK_SLEEP_NOW:
+               netif_device_detach(dev);
                /* prolly should wait for dma to finish & turn off the chip */
-               disable_irq(bmac_devs->irq);
+               save_flags(flags); cli();
+               if (bp->timeout_active) {
+                       del_timer(&bp->tx_timeout);
+                       bp->timeout_active = 0;
+               }
+               disable_irq(dev->irq);
                disable_irq(bp->tx_dma_intr);
                disable_irq(bp->rx_dma_intr);
+               bp->sleeping = 1;
+               restore_flags(flags);
+               if (bp->opened) {
+                       volatile struct dbdma_regs *rd = bp->rx_dma;
+                       volatile struct dbdma_regs *td = bp->tx_dma;
+                       
+                       config = bmread(dev, RXCFG);
+                       bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+                       config = bmread(dev, TXCFG);
+                       bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+                       bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+                       /* disable rx and tx dma */
+                       st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));       /* clear run bit */
+                       st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));       /* clear run bit */
+                       /* free some skb's */
+                       for (i=0; i<N_RX_RING; i++) {
+                               if (bp->rx_bufs[i] != NULL) {
+                                       dev_kfree_skb(bp->rx_bufs[i]);
+                                       bp->rx_bufs[i] = NULL;
+                               }
+                       }
+                       for (i = 0; i<N_TX_RING; i++) {
+                               if (bp->tx_bufs[i] != NULL) {
+                                       dev_kfree_skb(bp->tx_bufs[i]);
+                                       bp->tx_bufs[i] = NULL;
+                               }
+                       }
+               }
                feature_set(bp->node, FEATURE_BMac_reset);
-               udelay(10000);
+               mdelay(10);
                feature_clear(bp->node, FEATURE_BMac_IO_enable);
-               udelay(10000);
+               mdelay(10);
                break;
        case PBOOK_WAKE:
                /* see if this is enough */
-               bmac_reset_and_enable(bmac_devs);
-               enable_irq(bmac_devs->irq);
+               if (bp->opened)
+                       bmac_reset_and_enable(dev);
+               enable_irq(dev->irq);
                enable_irq(bp->tx_dma_intr);
                enable_irq(bp->rx_dma_intr);
+               netif_device_attach(dev);
                break;
        }
        return PBOOK_SLEEP_OK;
@@ -975,6 +1017,9 @@ static void bmac_set_multicast(struct net_device *dev)
        unsigned short rx_cfg;
        int i;
 
+       if (bp->sleeping)
+               return;
+
        XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
 
        if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
@@ -1228,7 +1273,8 @@ static void bmac_reset_and_enable(struct net_device *dev)
        bmac_init_chip(dev);
        bmac_start_chip(dev);
        bmwrite(dev, INTDISABLE, EnableNormal);
-
+       bp->sleeping = 0;
+       
        /*
         * It seems that the bmac can't receive until it's transmitted
         * a packet.  So we give it a dummy packet to transmit.
@@ -1396,8 +1442,10 @@ err_out:
 
 static int bmac_open(struct net_device *dev)
 {
+       struct bmac_data *bp = (struct bmac_data *) dev->priv;
        /* XXDEBUG(("bmac: enter open\n")); */
        /* reset the chip */
+       bp->opened = 1;
        bmac_reset_and_enable(dev);
        dev->flags |= IFF_RUNNING;
        return 0;
@@ -1443,6 +1491,8 @@ static int bmac_close(struct net_device *dev)
        }
        XXDEBUG(("bmac: all bufs freed\n"));
 
+       bp->opened = 0;
+
        return 0;
 }
 
@@ -1454,6 +1504,9 @@ bmac_start(struct net_device *dev)
        struct sk_buff *skb;
        unsigned long flags;
 
+       if (bp->sleeping)
+               return;
+               
        save_flags(flags); cli();
        while (1) {
                i = bp->tx_fill + 1;
index 9f9a6b9f1e25b2a02e5d39878875957694bc3a84..21a638ecd2862f424acebcf20a90f32bcdb956f2 100644 (file)
  * BenH <benh@kernel.crashing.org> - 03/09/2000
  * - Add support for new PHYs
  * - Add some PowerBook sleep code
- * 
+ * BenH <benh@kernel.crashing.org> - ??/??/????
+ *  - PHY updates
+ * BenH <benh@kernel.crashing.org> - 08/08/2001
+ * - Add more PHYs, fixes to sleep code
  */
 
 #include <linux/module.h>
@@ -46,8 +49,8 @@
 
 #define DEBUG_PHY
 
-/* Driver version 1.3, kernel 2.4.x */
-#define GMAC_VERSION   "v1.4k4"
+/* Driver version 1.5, kernel 2.4.x */
+#define GMAC_VERSION   "v1.5k4"
 
 #define DUMMY_BUF_LEN  RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN
 static unsigned char *dummy_buf;
@@ -213,7 +216,7 @@ mii_interrupt(struct gmac *gm)
                int             link_100 = 0;
                int             gigabit = 0;
 #ifdef DEBUG_PHY
-               printk("%s: Link state change, phy_status: 0x%04x\n",
+               printk(KERN_INFO "%s: Link state change, phy_status: 0x%04x\n",
                        gm->dev->name, phy_status);
 #endif
                gm->phy_status = phy_status;
@@ -228,37 +231,49 @@ mii_interrupt(struct gmac *gm)
                /* Link ? Check for speed and duplex */
                if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) {
                    int restart = 0;
-                   if (gm->phy_type == PHY_B5201) {
-                       int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
+                   int aux_stat, link;
+                   switch (gm->phy_type) {
+                     case PHY_B5201:
+                     case PHY_B5221:
+                       aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
 #ifdef DEBUG_PHY
-                       printk("    Link up ! BCM5201 aux_stat: 0x%04x\n", aux_stat);
+                       printk(KERN_INFO "%s:    Link up ! BCM5201/5221 aux_stat: 0x%04x\n",
+                               gm->dev->name, aux_stat);
 #endif
                        full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
                        link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
-                   } else if (gm->phy_type == PHY_B5400) {
-                       int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS);
-                       int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+                       break;
+                     case PHY_B5400:
+                     case PHY_B5401:
+                     case PHY_B5411:
+                       aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS);
+                       link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
                                        MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
 #ifdef DEBUG_PHY
-                       printk("    Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n",
-                               aux_stat, link);
+                       printk(KERN_INFO "%s:    Link up ! BCM54xx aux_stat: 0x%04x (link mode: %d)\n",
+                               gm->dev->name, aux_stat, link);
 #endif
                        full_duplex = phy_BCM5400_link_table[link][0];
                        link_100 = phy_BCM5400_link_table[link][1];
                        gigabit = phy_BCM5400_link_table[link][2];
-                   } else if (gm->phy_type == PHY_LXT971) {
-                       int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
+                       break;
+                     case PHY_LXT971:
+                       aux_stat = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
 #ifdef DEBUG_PHY
-                       printk("    Link up ! LXT971 stat2: 0x%04x\n", stat2);
+                       printk(KERN_INFO "%s:    Link up ! LXT971 stat2: 0x%04x\n",
+                               gm->dev->name, aux_stat);
 #endif
-                       full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
-                       link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0);
-                   } else {
+                       full_duplex = ((aux_stat & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
+                       link_100 = ((aux_stat & MII_LXT971_STATUS2_SPEED) != 0);
+                       break;
+                     default:
                        full_duplex = (lpar_ability & MII_ANLPA_FDAM) != 0;
                        link_100 = (lpar_ability & MII_ANLPA_100M) != 0;
+                       break;
                    }
 #ifdef DEBUG_PHY
-                   printk("    full_duplex: %d, speed: %s\n", full_duplex,
+                   printk(KERN_INFO "%s:    Full Duplex: %d, Speed: %s\n",
+                       gm->dev->name, full_duplex,
                        gigabit ? "1000" : (link_100 ? "100" : "10"));
 #endif
                     if (gigabit != gm->gigabit) {
@@ -275,13 +290,15 @@ mii_interrupt(struct gmac *gm)
                        gmac_start_dma(gm);
                } else if (!(phy_status & MII_SR_LKS)) {
 #ifdef DEBUG_PHY
-                   printk("    Link down !\n");
+                   printk(KERN_INFO "%s:    Link down !\n", gm->dev->name);
 #endif
                }
        }
 }
 
 /* Power management: stop PHY chip for suspend mode
+ * 
+ * TODO: This will have to be modified is WOL is to be supported.
  */
 static void
 gmac_suspend(struct gmac* gm)
@@ -290,7 +307,7 @@ gmac_suspend(struct gmac* gm)
        unsigned long flags;
        
        gm->sleeping = 1;
-       netif_stop_queue(gm->dev);
+       netif_device_detach(gm->dev);
 
 
        spin_lock_irqsave(&gm->lock, flags);
@@ -318,7 +335,7 @@ gmac_suspend(struct gmac* gm)
        }
 
        /* Clear interrupts on 5201 */
-       if (gm->phy_type == PHY_B5201)
+       if (gm->phy_type == PHY_B5201 || gm->phy_type == PHY_B5221)
                mii_write(gm, gm->phy_addr, MII_BCM5201_INTERRUPT, 0);
                
        /* Drive MDIO high */
@@ -328,12 +345,6 @@ gmac_suspend(struct gmac* gm)
        data = mii_read(gm, gm->phy_addr, MII_ANLPA);
        mii_write(gm, gm->phy_addr, MII_ANLPA, data);
        
-       /* Put MDIO in sane state */
-       GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB);
-       GM_OUT(GM_MIF_BB_CLOCK, 0);
-       GM_OUT(GM_MIF_BB_DATA, 0);
-       GM_OUT(GM_MIF_BB_OUT_ENABLE, 0);
-       
        /* Stop everything */
        GM_OUT(GM_MAC_RX_CONFIG, 0);
        GM_OUT(GM_MAC_TX_CONFIG, 0);
@@ -341,7 +352,7 @@ gmac_suspend(struct gmac* gm)
        GM_OUT(GM_TX_CONF, 0);
        GM_OUT(GM_RX_CONF, 0);
        
-       /* Set reset state */
+       /* Set MAC in reset state */
        GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);
        for (timeout = 100; timeout > 0; --timeout) {
                mdelay(10);
@@ -352,11 +363,23 @@ gmac_suspend(struct gmac* gm)
        GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW);
 
        /* Superisolate PHY */
-       if (gm->phy_type == PHY_B5201)
+       if (gm->phy_type == PHY_B5201 || gm->phy_type == PHY_B5221)
                mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY,
                        MII_BCM5201_MULTIPHY_SUPERISOLATE);
 
-       /* Unclock chip */
+       /* Put MDIO in sane electric state. According to an obscure
+        * Apple comment, not doing so may let them drive some current
+        * during sleep and possibly damage BCM PHYs.
+        */
+       GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB);
+       GM_OUT(GM_MIF_BB_CLOCK, 0);
+       GM_OUT(GM_MIF_BB_DATA, 0);
+       GM_OUT(GM_MIF_BB_OUT_ENABLE, 0);
+       GM_OUT(GM_MAC_XIF_CONFIG,
+               GM_MAC_XIF_CONF_GMII_MODE|GM_MAC_XIF_CONF_MII_INT_LOOP);
+       (void)GM_IN(GM_MAC_XIF_CONFIG);
+       
+       /* Unclock the GMAC chip */
        gmac_set_power(gm, 0);
 }
 
@@ -390,7 +413,7 @@ gmac_resume(struct gmac *gm)
        mdelay(20);
        GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);
        mdelay(20);
-       if (gm->phy_type == PHY_B5201) {
+       if (gm->phy_type == PHY_B5201 || gm->phy_type == PHY_B5221) {
                data = mii_read(gm, gm->phy_addr, MII_BCM5201_MULTIPHY);
                mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY,
                        data & ~MII_BCM5201_MULTIPHY_SUPERISOLATE);
@@ -402,7 +425,7 @@ gmac_resume(struct gmac *gm)
                mii_interrupt(gm);
                /* restart DMA operations */
                gmac_start_dma(gm);
-               netif_start_queue(gm->dev);
+               netif_device_attach(gm->dev);
                enable_irq(gm->dev->irq);
        } else {
                /* Driver not opened, just leave things off. Note that
@@ -446,11 +469,19 @@ mii_do_reset_phy(struct gmac *gm, int phy_addr)
        return 0;
 }
 
+/* Here's a bunch of configuration routines for
+ * Broadcom PHYs used on various Mac models. Unfortunately,
+ * except for the 5201, Broadcom never sent me any documentation,
+ * so this is from my understanding of Apple's Open Firmware
+ * drivers and Darwin's implementation
+ */
 static void
 mii_init_BCM5400(struct gmac *gm)
 {
        int data;
 
+       /* Configure for gigabit full duplex */
        data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL);
        data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
        mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data);
@@ -460,6 +491,8 @@ mii_init_BCM5400(struct gmac *gm)
        mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
        
        mdelay(10);
+
+       /* Reset and configure cascaded 10/100 PHY */
        mii_do_reset_phy(gm, 0x1f);
        
        data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY);
@@ -479,7 +512,14 @@ mii_init_BCM5401(struct gmac *gm)
 
        rev = mii_read(gm, gm->phy_addr, MII_ID1) & 0x000f;
        if (rev == 0 || rev == 3) {
-               /* A bit of black magic from Apple */
+               /* Some revisions of 5401 appear to need this
+                * initialisation sequence to disable, according
+                * to OF, "tap power management"
+                * 
+                * WARNING ! OF and Darwin don't agree on the
+                * register addresses. OF seem to interpret the
+                * register numbers below as decimal
+                */
                mii_write(gm, gm->phy_addr, 0x18, 0x0c20);
                mii_write(gm, gm->phy_addr, 0x17, 0x0012);
                mii_write(gm, gm->phy_addr, 0x15, 0x1804);
@@ -493,11 +533,14 @@ mii_init_BCM5401(struct gmac *gm)
                mii_write(gm, gm->phy_addr, 0x15, 0x0a20);
        }
        
+       /* Configure for gigabit full duplex */
        data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
        mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
 
        mdelay(10);
+
+       /* Reset and configure cascaded 10/100 PHY */
        mii_do_reset_phy(gm, 0x1f);
        
        data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY);
@@ -505,6 +548,34 @@ mii_init_BCM5401(struct gmac *gm)
        mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data);
 }
 
+static void
+mii_init_BCM5411(struct gmac *gm)
+{
+       int data;
+
+       /* Here's some more Apple black magic to setup
+        * some voltage stuffs.
+        */
+       mii_write(gm, gm->phy_addr, 0x1c, 0x8c23);
+       mii_write(gm, gm->phy_addr, 0x1c, 0x8ca3);
+       mii_write(gm, gm->phy_addr, 0x1c, 0x8c23);
+
+       /* Here, Apple seems to want to reset it, do
+        * it as well
+        */
+       mii_write(gm, gm->phy_addr, MII_CR, MII_CR_RST);
+
+       /* Start autoneg */
+       mii_write(gm, gm->phy_addr, MII_CR,
+                       MII_CR_ASSE|MII_CR_FDM| /* Autospeed, full duplex */
+                       MII_CR_RAN|
+                       MII_CR_SPEEDSEL2 /* chip specific, gigabit enable ? */);
+
+       data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);
+       data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+       mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
+}
+
 static int
 mii_lookup_and_reset(struct gmac *gm)
 {
@@ -536,29 +607,34 @@ mii_lookup_and_reset(struct gmac *gm)
        gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |
                mii_read(gm, gm->phy_addr, MII_ID1);
 #ifdef DEBUG_PHY
-       printk("%s PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);
+       printk(KERN_INFO "%s: PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);
 #endif
        if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {
                gm->phy_type = PHY_B5400;
-               printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n",
+               printk(KERN_INFO  "%s: Found Broadcom BCM5400 PHY (Gigabit)\n",
                        gm->dev->name);
                mii_init_BCM5400(gm);           
        } else if ((gm->phy_id & MII_BCM5401_MASK) == MII_BCM5401_ID) {
                gm->phy_type = PHY_B5401;
-               printk(KERN_ERR "%s Found Broadcom BCM5401 PHY (Gigabit)\n",
+               printk(KERN_INFO  "%s: Found Broadcom BCM5401 PHY (Gigabit)\n",
                        gm->dev->name);
                mii_init_BCM5401(gm);           
+       } else if ((gm->phy_id & MII_BCM5411_MASK) == MII_BCM5411_ID) {
+               gm->phy_type = PHY_B5411;
+               printk(KERN_INFO  "%s: Found Broadcom BCM5411 PHY (Gigabit)\n",
+                       gm->dev->name);
+               mii_init_BCM5411(gm);           
        } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {
                gm->phy_type = PHY_B5201;
-               printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name);
+               printk(KERN_INFO "%s: Found Broadcom BCM5201 PHY\n", gm->dev->name);
        } else if ((gm->phy_id & MII_BCM5221_MASK) == MII_BCM5221_ID) {
-               gm->phy_type = PHY_B5201; /* Same as 5201 for now */
-               printk(KERN_INFO "%s Found Broadcom BCM5221 PHY\n", gm->dev->name);
+               gm->phy_type = PHY_B5221;
+               printk(KERN_INFO "%s: Found Broadcom BCM5221 PHY\n", gm->dev->name);
        } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) {
                gm->phy_type = PHY_LXT971;
-               printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name);
+               printk(KERN_INFO "%s: Found LevelOne LX971 PHY\n", gm->dev->name);
        } else {
-               printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n",
+               printk(KERN_WARNING "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n",
                        gm->dev->name, gm->phy_id);
        }
 
index f4ab8481b4f4585b549372cae6f6b530d2b79b1b..a06dc8caf95e11f20e1343d27239d6dbe52db367 100644 (file)
 /*
 ** MII Management Control Register
 */
-#define MII_CR_RST  0x8000         /* RESET the PHY chip */
-#define MII_CR_LPBK 0x4000         /* Loopback enable */
-#define MII_CR_SPD  0x2000         /* 0: 10Mb/s; 1: 100Mb/s */
-#define MII_CR_10   0x0000         /* Set 10Mb/s */
-#define MII_CR_100  0x2000         /* Set 100Mb/s */
-#define MII_CR_ASSE 0x1000         /* Auto Speed Select Enable */
-#define MII_CR_PD   0x0800         /* Power Down */
-#define MII_CR_ISOL 0x0400         /* Isolate Mode */
-#define MII_CR_RAN  0x0200         /* Restart Auto Negotiation */
-#define MII_CR_FDM  0x0100         /* Full Duplex Mode */
-#define MII_CR_CTE  0x0080         /* Collision Test Enable */
-
+#define MII_CR_RST      0x8000         /* RESET the PHY chip */
+#define MII_CR_LPBK     0x4000         /* Loopback enable */
+#define MII_CR_SPD      0x2000         /* 0: 10Mb/s; 1: 100Mb/s */
+#define MII_CR_10       0x0000         /* Set 10Mb/s */
+#define MII_CR_100      0x2000         /* Set 100Mb/s */
+#define MII_CR_ASSE     0x1000         /* Auto Speed Select Enable */
+#define MII_CR_PD       0x0800         /* Power Down */
+#define MII_CR_ISOL     0x0400         /* Isolate Mode */
+#define MII_CR_RAN      0x0200         /* Restart Auto Negotiation */
+#define MII_CR_FDM      0x0100         /* Full Duplex Mode */
+#define MII_CR_CTE      0x0080         /* Collision Test Enable */
+#define MII_CR_SPEEDSEL2 0x0040                /* Speed selection 2 on BCM */
 /*
 ** MII Management Status Register
 */
 /* Supported PHYs (phy_type field ) */
 #define PHY_B5400      0x5400
 #define PHY_B5401      0x5401
+#define PHY_B5411      0x5411
 #define PHY_B5201      0x5201
+#define PHY_B5221      0x5221
 #define PHY_LXT971     0x0971
 #define PHY_UNKNOWN    0
 
 #define MII_BCM5401_REV                         0x01
 #define MII_BCM5401_ID                          ((MII_BCM5401_OUI << 10) | (MII_BCM5401_MODEL << 4))
 #define MII_BCM5401_MASK                        0xfffffff0
+#define MII_BCM5411_OUI                         0x000818
+#define MII_BCM5411_MODEL                       0x07
+#define MII_BCM5411_REV                         0x01
+#define MII_BCM5411_ID                          ((MII_BCM5411_OUI << 10) | (MII_BCM5411_MODEL << 4))
+#define MII_BCM5411_MASK                        0xfffffff0
 #define MII_LXT971_OUI                          0x0004de
 #define MII_LXT971_MODEL                        0x0e
 #define MII_LXT971_REV                          0x00
index 351323cf339154639c0ac91c82872a524421b89b..b125faa21b960075b4a55d5e9224f42794ed0d84 100644 (file)
@@ -282,7 +282,7 @@ static inline void irda_usb_send_empty(struct irda_usb_cb *self)
                IRDA_DEBUG(0, __FUNCTION__ "(), failed Empty URB\n");
        }
 }
-#endif IU_BUG_KICK_TX
+#endif /* IU_BUG_KICK_TX */
 
 /*------------------------------------------------------------------*/
 /*
@@ -404,7 +404,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
         * insert empty packet to separate our frames.
         * This flag was previously called USB_DISABLE_SPD - Jean II */
        purb->transfer_flags |= USB_ZERO_PACKET;
-#endif IU_USE_USB_ZERO_FLAG
+#endif /* IU_USE_USB_ZERO_FLAG */
        purb->timeout = MSECS_TO_JIFFIES(100);
        
        /* Generate min turn time. FIXME: can we do better than this? */
@@ -472,7 +472,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
                        IRDA_DEBUG(2, __FUNCTION__ "(), Kick Tx...\n");
                        irda_usb_send_empty(self);
                }
-#endif IU_BUG_KICK_TX
+#endif /* IU_BUG_KICK_TX */
        }
        spin_unlock_irqrestore(&self->lock, flags);
        
@@ -580,7 +580,7 @@ static void irda_usb_net_timeout(struct net_device *netdev)
                        break;
                }
        }
-#endif IU_BUG_KICK_TX
+#endif /* IU_BUG_KICK_TX */
 
        /* Check speed URB */
        purb = &(self->speed_urb);
@@ -624,7 +624,7 @@ static void irda_usb_net_timeout(struct net_device *netdev)
                if(self->new_xbofs == -1)
                        self->new_xbofs = self->xbofs;
                irda_usb_change_speed_xbofs(self);
-#endif IU_BUG_KICK_TIMEOUT
+#endif /* IU_BUG_KICK_TIMEOUT */
 
                switch (purb->status) {
                case -ECONNABORTED:             /* -103 */
@@ -1325,7 +1325,7 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
        printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
        printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
 }
-#endif IU_DUMP_CLASS_DESC
+#endif /* IU_DUMP_CLASS_DESC */
 
 /*------------------------------------------------------------------*/
 /*
@@ -1370,7 +1370,7 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device
        *desc = *ptr;
 #ifdef IU_DUMP_CLASS_DESC
        irda_usb_dump_class_desc(desc);
-#endif IU_DUMP_CLASS_DESC
+#endif /* IU_DUMP_CLASS_DESC */
        return desc;
 }
 
index 2eb810c808d7c12213023d05d5a21063fdc4b457..e9b4b940aaf7613c11bdef402a6b85b1d2836a4c 100644 (file)
 #include <linux/ip.h>  /* for iph */
 #include <linux/in.h>  /* for IPPROTO_... */
 #include <linux/eeprom.h>
+#include <linux/compiler.h>
 //#include <linux/skbrefill.h>
 
 /* Dprintk is used for more interesting debug events */
 #undef Dprintk
 #define        Dprintk                 dprintk
 
-#if !defined(GCC_VERSION) || (GCC_VERSION < 2096)
-#define __builtin_expect(x,y)  (x)
-#endif
-
 #ifdef CONFIG_HIGHMEM64G
 #define USE_64BIT_ADDR
 #elif defined(__ia64__)
index 64c0785aeb0f03a2f95025b6cfc674aa3d3801a5..4ca0b0e8774017f5e70989fa22b8fef6c3952c7e 100644 (file)
@@ -20,7 +20,8 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
    fi
 
    if [ "$CONFIG_CARDBUS" = "y" ]; then
-      tristate '  Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP
+      tristate '  Xircom CardBus support (new driver)' CONFIG_PCMCIA_XIRCOM
+      tristate '  Xircom Tulip-like CardBus support (old driver)' CONFIG_PCMCIA_XIRTULIP
    fi
 
    bool '  Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
index ca1634206d0f818d17372c26c25cc439b436f046..3de15cfde3821d87876e4d1a15e83c1dc44cba8c 100644 (file)
@@ -32,7 +32,9 @@ obj-$(CONFIG_AIRONET4500_CS)  += aironet4500_cs.o
 
 # Cardbus client drivers
 obj-$(CONFIG_PCMCIA_XIRTULIP)  += xircom_tulip_cb.o
+obj-$(CONFIG_PCMCIA_XIRCOM)    += xircom_cb.o
 
 obj-$(CONFIG_PCMCIA_IBMTR)     += ibmtr_cs.o
 
 include $(TOPDIR)/Rules.make
+
diff --git a/drivers/net/pcmcia/xircom_cb.c b/drivers/net/pcmcia/xircom_cb.c
new file mode 100644 (file)
index 0000000..a256a5b
--- /dev/null
@@ -0,0 +1,1410 @@
+/*
+ * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards 
+ *
+ * This software is Copyright 2001 by the respective authors, and licensed under the GPL
+ * License.
+ *
+ * Written by Arjan van de Ven for Red Hat, Inc.
+ * Based on work by Jeff Garzik, Doug Ledford, Donald Becker and Ion Badulescu
+ *
+ *     This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ *     $Id: xircom_cb.c,v 1.11 2001/06/05 09:50:57 fenrus Exp $
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+
+
+#ifdef DEBUG
+#define enter()   printk("Enter: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)
+#define leave()   printk("Leave: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)
+#else
+#define enter()   do {} while (0)
+#define leave()   do {} while (0)
+#endif
+
+
+MODULE_DESCRIPTION("Xircom Cardbus ethernet driver");
+MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>");
+
+
+
+/* IO registers on the card, offsets */
+#define CSR0   0x00
+#define CSR1   0x08
+#define CSR2   0x10
+#define CSR3   0x18
+#define CSR4   0x20
+#define CSR5   0x28
+#define CSR6   0x30
+#define CSR7   0x38
+#define CSR8   0x40
+#define CSR9   0x48
+#define CSR10  0x50
+#define CSR11  0x58
+#define CSR12  0x60
+#define CSR13  0x68
+#define CSR14  0x70
+#define CSR15  0x78
+#define CSR16  0x80
+
+/* PCI registers */
+#define PCI_POWERMGMT  0x40
+
+/* Offsets of the buffers within the descriptor pages, in bytes */
+
+#define NUMDESCRIPTORS 4
+#define RXTXBUFSIZE 8192
+#define MAX_PACKETSIZE 1536
+
+
+#define DescOwnedCard  0x80000000
+#define DescOwnedDriver        0x00000000
+
+#define PromiscBit             (1<<6)
+#define CollisionBit           (1<<8)
+#define TxActiveBit            (1<<13)
+#define RxActiveBit            (1<<1)
+#define LastDescBit            (1<<25)
+#define LinkStatusBit          (1<<27)
+
+#define PowerMgmtBits          ( (1<<31)|(1<<30) )
+
+static const unsigned int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};
+
+/* note: this struct is assumed to be packed as this is the "hardware" layout */
+struct descriptor {
+       u32     status;
+       u32     control;
+       u32     address1;
+       u32     address2;
+};
+
+
+struct xircom_private {
+       /* Send and receive buffers, kernel-addressable and dma addressable forms */
+
+       unsigned char *rx_buffer;
+       unsigned char *tx_buffer;
+       
+       struct descriptor *rx_desc;
+       struct descriptor *tx_desc;
+
+       dma_addr_t rx_dma_handle;
+       dma_addr_t tx_dma_handle;
+
+       struct sk_buff *tx_skb[NUMDESCRIPTORS];
+
+       unsigned long io_port;
+       
+       /* transmit_used is the rotating counter that indicates which transmit
+          descriptor has to be used next */
+       unsigned int transmit_used;
+
+       /* Spinlock to serialize register operations.
+          It must be helt while manipulating the following registers:
+          CSR0, CSR6, CSR7, CSR9, CSR10, CSR15
+        */
+       spinlock_t lock;
+
+
+       struct pci_dev *pdev;
+       struct net_device *dev;
+       struct net_device_stats stats;
+};
+
+
+/* Function prototypes */
+static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void xircom_remove(struct pci_dev *pdev);
+static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int xircom_open(struct net_device *dev);
+static int xircom_close(struct net_device *dev);
+static void xircom_up(struct xircom_private *card);
+static struct net_device_stats *xircom_get_stats(struct net_device *dev);
+
+static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);
+static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset);
+static void read_mac_address(struct xircom_private *card);
+static void tranceiver_voodoo(struct xircom_private *card);
+static void initialize_card(struct xircom_private *card);
+static inline void trigger_transmit(struct xircom_private *card);
+static inline void trigger_receive(struct xircom_private *card);
+static void setup_descriptors(struct xircom_private *card);
+static inline void remove_descriptors(struct xircom_private *card);
+static inline unsigned int link_status_changed(struct xircom_private *card);
+static void activate_receiver(struct xircom_private *card);
+static void deactivate_receiver(struct xircom_private *card);
+static void activate_transmitter(struct xircom_private *card);
+static void deactivate_transmitter(struct xircom_private *card);
+static void enable_transmit_interrupt(struct xircom_private *card);
+static void enable_receive_interrupt(struct xircom_private *card);
+static void enable_link_interrupt(struct xircom_private *card);
+static void disable_all_interrupts(struct xircom_private *card);
+static inline unsigned int link_status(struct xircom_private *card);
+static int mdio_read(struct xircom_private *card, int phy_id, int location);
+static void mdio_write(struct xircom_private *card, int phy_id, int location, int value);
+
+
+
+static struct pci_device_id xircom_pci_table[] __devinitdata = {
+       {0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,},
+       {0,},
+};
+MODULE_DEVICE_TABLE(pci, xircom_pci_table);
+
+static struct pci_driver xircom_ops = {
+       name:           "xircom_cb", 
+       id_table:       xircom_pci_table, 
+       probe:          xircom_probe, 
+       remove:         xircom_remove, 
+};
+
+
+#ifdef DEBUG
+static void print_binary(unsigned int number)
+{
+       int i,i2;
+       char buffer[64];
+       memset(buffer,0,64);
+       i2=0;
+       for (i=31;i>=0;i--) {
+               if (number & (1<<i))
+                       buffer[i2++]='1';
+               else
+                       buffer[i2++]='0';
+               if ((i&3)==0) 
+                       buffer[i2++]=' ';
+       }
+       printk("%s\n",buffer);
+}
+#endif
+
+/* xircom_probe is the code that gets called on device insertion.
+   it sets up the hardware and registers the device to the networklayer.
+   
+   TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the
+         first two packets that get send, and pump hates that.
+         
+ */
+static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct net_device *dev = NULL;
+       struct xircom_private *private;
+       u8 chip_rev;
+       unsigned long flags;
+       u32 tmp32;
+       u16 tmp16;
+       int ret;
+       enter();
+       
+       /* First do the PCI initialisation */
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       /* disable all powermanagement */
+       pci_read_config_dword(pdev, PCI_POWERMGMT,&tmp32);
+       tmp32 &= ~PowerMgmtBits; 
+       pci_write_config_dword(pdev, PCI_POWERMGMT, tmp32);
+       
+       pci_set_master(pdev); 
+
+       /* clear PCI status, if any */ 
+       pci_read_config_word (pdev,PCI_STATUS, &tmp16); 
+       pci_write_config_word (pdev, PCI_STATUS,tmp16);
+       
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
+       
+       if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
+               printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
+               return -ENODEV;
+       }
+
+       
+       dev = init_etherdev(dev, sizeof(*private));
+       if (dev == NULL) {
+               printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
+               return -ENODEV;
+       }
+       SET_MODULE_OWNER(dev);
+       private = dev->priv;
+       if (private==NULL) {
+               printk(KERN_ERR "xircom_probe: failed to allocate private device struct\n");
+               return -ENODEV;
+       }
+               
+       /* Allocate the send/receive buffers */
+       private->rx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->rx_dma_handle);
+       if (private->rx_buffer == NULL) {
+               printk(KERN_ERR "xircom_probe: no memory for rx buffer \n");
+               kfree(private);
+               return -ENODEV;
+       }       
+       /* the descriptors are stored in the first bytes of the rx_buffer, hence the ugly cast */
+       private->rx_desc = (struct descriptor *)private->rx_buffer;
+
+       private->tx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->tx_dma_handle);
+       if (private->tx_buffer == NULL) {
+               printk(KERN_ERR "xircom_probe: no memory for tx buffer \n");
+               kfree(private->rx_buffer);
+               kfree(private);
+               return -ENODEV;
+       }
+       /* the descriptors are stored in the first bytes of the tx_buffer, hence the ugly cast */
+       private->tx_desc = (struct descriptor *)private->tx_buffer;
+       
+       
+       printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
+
+       private->dev = dev;
+       private->pdev = pdev;
+       private->io_port = pci_resource_start(pdev, 0);
+       private->lock = SPIN_LOCK_UNLOCKED;
+       dev->irq = pdev->irq;
+       dev->base_addr = private->io_port;
+       
+       
+       initialize_card(private);
+       read_mac_address(private);
+       setup_descriptors(private);
+       
+       dev->open = &xircom_open;
+       dev->hard_start_xmit = &xircom_start_xmit;
+       dev->stop = &xircom_close;
+       dev->get_stats = &xircom_get_stats;
+       dev->priv = private;
+       pci_set_drvdata(pdev,dev);
+
+       
+       /* start the transmitter to get a heartbeat; don't do
+          that when there already is one though; Cisco's 
+          really don't like that. */
+       if (!link_status(private))
+               tranceiver_voodoo(private);
+       
+       spin_lock_irqsave(&private->lock,flags);
+         activate_transmitter(private);
+         activate_receiver(private);
+       spin_unlock_irqrestore(&private->lock,flags);
+
+       /* TODO: send 2 dummy packets here */
+       
+       trigger_receive(private);
+       
+       leave();
+       return 0;
+}
+
+
+/*
+ xircom_remove is called on module-unload or on device-eject.
+ it unregisters the irq, io-region and network device.
+ Interrupts and such are already stopped in the "ifconfig ethX down"
+ code.
+ */
+static void __devexit xircom_remove(struct pci_dev *pdev)
+{
+       struct net_device *dev = pdev->driver_data;
+       struct xircom_private *card;
+       enter();
+       
+       card=dev->priv;
+
+       if (card->rx_buffer!=NULL)
+               pci_free_consistent(pdev,RXTXBUFSIZE,card->rx_buffer,card->rx_dma_handle);
+       card->rx_buffer = NULL;
+       card->rx_desc = NULL;
+       if (card->tx_buffer!=NULL)
+               pci_free_consistent(pdev,RXTXBUFSIZE,card->tx_buffer,card->tx_dma_handle);
+       card->tx_buffer = NULL;                 
+       card->tx_desc = NULL;
+
+       release_region(dev->base_addr, 128);
+       unregister_netdev(dev);
+       kfree(dev);
+       pci_set_drvdata(pdev,NULL);
+       leave();
+} 
+
+static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+       struct net_device *dev = dev_instance;
+       struct xircom_private *card = dev->priv;
+       u32 status;
+       unsigned int xmit_free_count;
+       unsigned int i;
+
+       enter();
+
+
+       spin_lock(&card->lock);
+       status = inl(card->io_port+CSR5);
+       if (status==0xffffffff) {/* card has been ejected / powered down */
+               spin_unlock(&card->lock);
+               return;
+       }
+
+       /* Todo: check if there were any events at all; to speed up
+          returning if we're on a shared interrupt */  
+
+       if (link_status_changed(card)) {
+               int newlink;
+               printk(KERN_DEBUG "xircom_cb: Link status has changed \n");
+               newlink = link_status(card);
+               if (newlink) {
+                       printk(KERN_INFO  "xircom_cb: Link is %i mbit \n",newlink);
+                       netif_carrier_on(dev);
+               } else {
+                       printk(KERN_INFO  "xircom_cb: Link is absent \n");
+                       netif_carrier_off(dev);
+               }
+       }
+
+       /* Clear all remaining interrupt events */      
+       status |= 0xffffffff; /* FIXME: make this clear only the
+                                       real existing bits */
+       outl(status,card->io_port+CSR5);
+       
+       xmit_free_count = 0;
+
+       for (i=0;i<NUMDESCRIPTORS;i++) 
+               xmit_free_count += investigate_tx_descriptor(dev,card,i,bufferoffsets[i]);
+       for (i=0;i<NUMDESCRIPTORS;i++) 
+               investigate_rx_descriptor(dev,card,i,bufferoffsets[i]);
+
+       
+       if (xmit_free_count)
+               netif_start_queue(dev);
+               
+       spin_unlock(&card->lock);
+       leave();
+}
+
+static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct xircom_private *card;
+       unsigned long flags;
+       unsigned int nextdescriptor;
+       unsigned int desc;
+       enter();
+       
+       card = (struct xircom_private*)dev->priv;
+
+       spin_lock_irqsave(&card->lock,flags);
+       
+       nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS);
+       desc = card->transmit_used;
+       
+       /* only send the packet if the descriptor is free */
+       if (card->tx_desc[desc].status==0) {
+                       /* Copy the packet data; zero the memory first as the card
+                          sometimes sends more than you ask it to. */
+                       
+                       memset(&card->tx_buffer[bufferoffsets[desc]],0,MAX_PACKETSIZE);
+                       memcpy(&(card->tx_buffer[bufferoffsets[desc]]),skb->data,skb->len);
+       
+       
+                       /* FIXME: The specification tells us that the length we send HAS to be a multiple of
+                          4 bytes. */
+                          
+                       card->tx_desc[desc].control = skb->len;
+                       if (desc == NUMDESCRIPTORS-1)
+                               card->tx_desc[desc].control |= LastDescBit;  /* bit 25: last descriptor of the ring */
+
+                       card->tx_desc[desc].control |= 0xF0000000;
+                                                /* 0xF0... means want interrupts*/ 
+                       card->tx_skb[desc] = skb;
+                       
+                       wmb();
+                       /* This gives the descriptor to the card */
+                       card->tx_desc[desc].status = DescOwnedCard;
+                       trigger_transmit(card);
+                       if (((int)card->tx_desc[nextdescriptor].status)<0) {    /* next descriptor is occupied... */
+                               netif_stop_queue(dev);
+                       }
+                       card->transmit_used = nextdescriptor;
+                       spin_unlock_irqrestore(&card->lock,flags);
+                       leave();
+                       return 0;
+       }
+       
+
+
+       /* Uh oh... no free descriptor... drop the packet */
+       /* This should not happen in theory...*/
+       netif_stop_queue(dev);
+       spin_unlock_irqrestore(&card->lock,flags);
+       trigger_transmit(card);
+       leave();
+       
+       return -EIO;
+}
+
+
+
+
+static int xircom_open(struct net_device *dev)
+{
+       struct xircom_private *xp = (struct xircom_private *) dev->priv;
+       int retval;
+       enter();
+       printk(KERN_INFO "Xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
+       retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev);
+       if (retval) {
+               printk(KERN_ERR "xircom_cb: Unable to aquire IRQ %i, aborting.\n",dev->irq);
+               leave();
+               return retval;
+       }
+       
+       xircom_up(xp);
+       leave();
+       return 0;
+}
+
+static int xircom_close(struct net_device *dev)
+{
+       struct xircom_private *card;
+       unsigned long flags;
+       
+       enter();
+       card = dev->priv;
+       netif_stop_queue(dev); /* we don't want to send new packets */
+
+       
+       spin_lock_irqsave(&card->lock,flags);
+       
+       disable_all_interrupts(card);
+#if 0  
+       /* We can enable this again once we send dummy packets on ifconfig ethX up */
+       deactivate_receiver(card);
+       deactivate_transmitter(card);
+#endif 
+       remove_descriptors(card);
+       
+       spin_unlock_irqrestore(&card->lock,flags);
+       
+       free_irq(dev->irq,dev);
+       
+       leave();
+               
+       return 0;
+       
+}
+
+
+
+static struct net_device_stats *xircom_get_stats(struct net_device *dev)
+{
+        struct xircom_private *card = (struct xircom_private *)dev->priv;
+        return &card->stats;
+} 
+                                                 
+
+
+
+static void initialize_card(struct xircom_private *card)
+{
+       unsigned int val;
+       unsigned long flags;
+       enter();
+
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       /* First: reset the card */
+       val = inl(card->io_port + CSR0);
+       val |= 0x01;            /* Software reset */
+       outl(val, card->io_port + CSR0);
+
+       udelay(100);            /* give the card some time to reset */
+
+       val = inl(card->io_port + CSR0);
+       val &= ~0x01;           /* disable Software reset */
+       outl(val, card->io_port + CSR0);
+
+
+       val = 0;                /* Value 0x00 is a safe and conservative value 
+                                  for the PCI configuration settings */
+       outl(val, card->io_port + CSR0);
+
+
+       disable_all_interrupts(card);
+       deactivate_receiver(card);
+       deactivate_transmitter(card);
+
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       leave();
+}
+
+/*
+trigger_transmit causes the card to check for frames to be transmitted.
+This is accomplished by writing to the CSR1 port. The documentation
+claims that the act of writing is sufficient and that the value is
+ignored; I chose zero.
+*/
+static inline void trigger_transmit(struct xircom_private *card)
+{
+       enter();
+       outl(0, card->io_port + CSR1);
+       leave();
+}
+
+/*
+trigger_receive causes the card to check for empty frames in the
+descriptor list in which packets can be received.
+This is accomplished by writing to the CSR2 port. The documentation
+claims that the act of writing is sufficient and that the value is
+ignored; I chose zero.
+*/
+static inline void trigger_receive(struct xircom_private *card)
+{
+       enter();
+       outl(0, card->io_port + CSR2);
+       leave();
+}
+
+/*
+setup_descriptors initializes the send and receive buffers to be valid
+descriptors and programs the addresses into the card.
+*/
+static void setup_descriptors(struct xircom_private *card)
+{
+       unsigned int val;
+       u32 address;
+       unsigned int i;
+       enter();
+
+
+       if (card->rx_buffer == NULL)
+               BUG();
+       if (card->tx_buffer == NULL)
+               BUG();
+
+       /* Receive descriptors */
+       memset(card->rx_desc, 0, 128);  /* clear the descriptors */
+       for (i=0;i<NUMDESCRIPTORS;i++ ) {
+
+               /* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */
+               card->rx_desc[i].status = DescOwnedCard;
+               /* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
+               card->rx_desc[i].control = MAX_PACKETSIZE;
+               if (i==NUMDESCRIPTORS-1)
+                       card->rx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */
+
+               /* Rx Descr2: address of the buffer
+                  we store the buffer at the 2nd half of the page */
+       
+               address = card->rx_dma_handle;
+               
+               card->rx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]);
+               /* Rx Desc3: address of 2nd buffer -> 0 */
+               card->rx_desc[i].address2 = 0;
+       }
+       
+       wmb();
+       /* Write the receive descriptor ring address to the card */
+       address = card->rx_dma_handle;
+       val = cpu_to_le32(address); 
+       outl(val, card->io_port + CSR3);        /* Receive descr list address */
+
+
+       /* transmit descriptors */
+       memset(card->tx_desc, 0, 128);  /* clear the descriptors */
+       
+       for (i=0;i<NUMDESCRIPTORS;i++ ) {
+               /* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */
+               card->tx_desc[i].status = DescOwnedDriver;
+               /* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
+               card->tx_desc[i].control = MAX_PACKETSIZE;
+               if (i==NUMDESCRIPTORS-1)
+                       card->tx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */
+               
+               /* Tx Descr2: address of the buffer
+                  we store the buffer at the 2nd half of the page */
+               address = card->tx_dma_handle;
+               card->tx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]);
+               /* Tx Desc3: address of 2nd buffer -> 0 */
+               card->tx_desc[i].address2 = 0;
+       }
+
+       wmb();
+       /* wite the transmit descriptor ring to the card */
+       address = card->tx_dma_handle;
+       val =cpu_to_le32(address);
+       outl(val, card->io_port + CSR4);        /* xmit descr list address */
+
+       leave();
+}
+
+/*
+remove_descriptors informs the card the descriptors are no longer
+valid by setting the address in the card to 0x00.
+*/
+static inline void remove_descriptors(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = 0;
+       outl(val, card->io_port + CSR3);        /* Receive descriptor address */
+       outl(val, card->io_port + CSR4);        /* Send descriptor address */
+
+       leave();
+}
+
+/*
+link_status_changed returns 1 if the card has indicated that
+the link status has changed. The new link status has to be read from CSR12.
+
+This function also clears the status-bit.
+*/
+static inline unsigned int link_status_changed(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR5);        /* Status register */
+
+       if ((val & LinkStatusBit) == 0) {       /* no change */
+               leave();
+               return 0;
+       }
+
+       /* clear the event by writing a 1 to the bit in the
+          status register. */
+       val = LinkStatusBit;
+       outl(val, card->io_port + CSR5);
+
+       leave();
+       return 1;
+}
+
+
+/*
+transmit_active returns 1 if the transmitter on the card is
+in a non-stopped state.
+*/
+static inline int transmit_active(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR5);        /* Status register */
+
+       if ((val & (7 << 20)) == 0) {   /* transmitter disabled */
+               leave();
+               return 0;
+       }
+
+       leave();
+       return 1;
+}
+
+/*
+receive_active returns 1 if the receiver on the card is
+in a non-stopped state.
+*/
+static inline unsigned int receive_active(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+
+       val = inl(card->io_port + CSR5);        /* Status register */
+
+       if ((val & (7 << 17)) == 0) {   /* receiver disabled */
+               leave();
+               return 0;
+       }
+
+       leave();
+       return 1;
+}
+
+/*
+activate_receiver enables the receiver on the card.
+Before being allowed to active the receiver, the receiver
+must be completely de-activated. To achieve this,
+this code actually disables the receiver first; then it waits for the 
+receiver to become inactive, then it activates the receiver and then
+it waits for the receiver to be active.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void activate_receiver(struct xircom_private *card)
+{
+       unsigned int val;
+       int counter;
+       enter();
+
+
+       val = inl(card->io_port + CSR6);        /* Operation mode */
+       
+       /* If the "active" bit (1) is set and the receiver is already
+          active, no need to do the expensive thing */
+       if ((val& RxActiveBit) && (receive_active(card)))
+               return;
+       
+       
+       val = val & ~RxActiveBit;               /* disable the receiver */
+       outl(val, card->io_port + CSR6);
+
+       counter = 10;
+       while (counter > 0) {
+               if (!receive_active(card))
+                       break;
+               /* wait a while */
+               udelay(50);
+               counter--;
+               if (counter <= 0)
+                       printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+       }
+
+       /* enable the receiver */
+       val = inl(card->io_port + CSR6);        /* Operation mode */
+       val = val | RxActiveBit;                /* enable the receiver */
+       outl(val, card->io_port + CSR6);
+
+       /* now wait for the card to activate again */
+       counter = 10;
+       while (counter > 0) {
+               if (receive_active(card))
+                       break;
+               /* wait a while */
+               udelay(50);
+               counter--;
+               if (counter <= 0)
+                       printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n");
+       }
+
+       leave();
+}
+
+/*
+deactivate_receiver disables the receiver on the card.
+To achieve this this code disables the receiver first; 
+then it waits for the receiver to become inactive.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void deactivate_receiver(struct xircom_private *card)
+{
+       unsigned int val;
+       int counter;
+       enter();
+
+       val = inl(card->io_port + CSR6);        /* Operation mode */
+       val = val & ~RxActiveBit;               /* disable the receiver */
+       outl(val, card->io_port + CSR6);
+
+       counter = 10;
+       while (counter > 0) {
+               if (!receive_active(card))
+                       break;
+               /* wait a while */
+               udelay(50);
+               counter--;
+               if (counter <= 0)
+                       printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+       }
+
+
+       leave();
+}
+
+
+/*
+activate_transmitter enables the transmitter on the card.
+Before being allowed to active the transmitter, the transmitter
+must be completely de-activated. To achieve this,
+this code actually disables the transmitter first; then it waits for the 
+transmitter to become inactive, then it activates the transmitter and then
+it waits for the transmitter to be active again.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void activate_transmitter(struct xircom_private *card)
+{
+       unsigned int val;
+       int counter;
+       enter();
+
+
+       val = inl(card->io_port + CSR6);        /* Operation mode */
+
+       /* If the "active" bit (13) is set and the receiver is already
+          active, no need to do the expensive thing */  
+       if ((val & TxActiveBit) && (transmit_active(card)))
+               return;
+
+       val = val & ~TxActiveBit;       /* disable the transmitter */
+       outl(val, card->io_port + CSR6);
+
+       counter = 10;
+       while (counter > 0) {
+               if (!transmit_active(card))
+                       break;
+               /* wait a while */
+               udelay(50);
+               counter--;
+               if (counter <= 0)
+                       printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+       }
+
+       /* enable the transmitter */
+       val = inl(card->io_port + CSR6);        /* Operation mode */
+       val = val | TxActiveBit;        /* enable the transmitter */
+       outl(val, card->io_port + CSR6);
+
+       /* now wait for the card to activate again */
+       counter = 10;
+       while (counter > 0) {
+               if (transmit_active(card))
+                       break;
+               /* wait a while */
+               udelay(50);
+               counter--;
+               if (counter <= 0)
+                       printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n");
+       }
+
+       leave();
+}
+
+/*
+deactivate_transmitter disables the transmitter on the card.
+To achieve this this code disables the transmitter first; 
+then it waits for the transmitter to become inactive.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void deactivate_transmitter(struct xircom_private *card)
+{
+       unsigned int val;
+       int counter;
+       enter();
+
+       val = inl(card->io_port + CSR6);        /* Operation mode */
+       val = val & ~TxActiveBit;               /* disable the transmitter */
+       outl(val, card->io_port + CSR6);
+
+       counter = 20;
+       while (counter > 0) {
+               if (!transmit_active(card))
+                       break;
+               /* wait a while */
+               udelay(50);
+               counter--;
+               if (counter <= 0)
+                       printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+       }
+
+
+       leave();
+}
+
+
+/*
+enable_transmit_interrupt enables the transmit interrupt
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_transmit_interrupt(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR7);        /* Interrupt enable register */
+       val |= 1;                               /* enable the transmit interrupt */
+       outl(val, card->io_port + CSR7);
+
+       leave();
+}
+
+
+/*
+enable_receive_interrupt enables the receive interrupt
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_receive_interrupt(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR7);        /* Interrupt enable register */
+       val = val | (1 << 6);                   /* enable the receive interrupt */
+       outl(val, card->io_port + CSR7);
+
+       leave();
+}
+
+/*
+enable_link_interrupt enables the link status change interrupt
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_link_interrupt(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR7);        /* Interrupt enable register */
+       val = val | LinkStatusBit;                      /* enable the link status chage interrupt */
+       outl(val, card->io_port + CSR7);
+
+       leave();
+}
+
+
+
+/*
+disable_all_interrupts disables all interrupts
+
+must be called with the lock held and interrupts disabled.
+*/
+static void disable_all_interrupts(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+       
+       val = 0;                                /* disable all interrupts */
+       outl(val, card->io_port + CSR7);
+
+       leave();
+}
+
+/*
+enable_common_interrupts enables several weird interrupts
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_common_interrupts(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR7);        /* Interrupt enable register */
+       val |= (1<<16); /* Normal Interrupt Summary */
+       val |= (1<<15); /* Abnormal Interrupt Summary */
+       val |= (1<<13); /* Fatal bus error */
+       val |= (1<<8);  /* Receive Process Stopped */
+       val |= (1<<7);  /* Receive Buffer Unavailable */
+       val |= (1<<5);  /* Transmit Underflow */
+       val |= (1<<2);  /* Transmit Buffer Unavailable */
+       val |= (1<<1);  /* Transmit Process Stopped */
+       outl(val, card->io_port + CSR7);
+
+       leave();
+}
+
+/*
+enable_promisc starts promisc mode
+
+must be called with the lock held and interrupts disabled.
+*/
+static inline void enable_promisc(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+
+       val = inl(card->io_port + CSR6);        
+       val = val | PromiscBit;  /* Bit 6 */
+       outl(val, card->io_port + CSR6);
+
+       printk(KERN_INFO "xircom_cb: enabling promiscuous mode \n");
+       leave();
+}
+
+
+
+
+/* 
+link_status() checks the the links status and will return 0 for no link, 
+10 for 10mbit link and 100 for.. guess what.
+
+Must be called in locked state with interrupts disabled
+*/
+static inline unsigned int link_status(struct xircom_private *card)
+{
+       unsigned int val;
+       enter();
+       
+       val = inb(card->io_port + CSR12);
+       
+       if (!(val&(1<<2)))  /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */
+               return 10;
+       if (!(val&(1<<1)))  /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */
+               return 100;
+               
+       /* If we get here -> no link at all */  
+
+       leave();
+       return 0;
+}
+
+
+
+/* 
+
+set_half_duplex() sets the card to half duplex mode. In order to do this,
+set_half_duplex() has to deactivate the transmitter and receiver first. It
+will re-enable the transmitter and receiver if those were active from the
+beginning.
+
+Update: the above is not enough. It doesn't touch the MII, in fact it ensures
+the main chipset and the MII are never in sync if a full-duplex connection
+is negotiated. The proper fix is to tell the MII to force a half-duplex
+connection. -Ion
+
+Must be called in locked state
+*/
+static void set_half_duplex(struct xircom_private *card)
+{
+       unsigned int val;
+       int rx,tx,tmp;
+       enter();
+       
+       rx=receive_active(card);
+       tx=transmit_active(card);
+       
+       deactivate_transmitter(card);
+       deactivate_receiver(card);
+       
+       val = inb(card->io_port + CSR6);
+       val &= ~(1<<9);
+       outb(val,card->io_port + CSR6);
+
+       /* tell the MII not to advertise 10/100FDX */
+       tmp = mdio_read(card, 0, 4);
+       printk("xircom_cb: capabilities changed from %#x to %#x\n",
+              tmp, tmp & ~0x140);
+       tmp &= ~0x140;
+       mdio_write(card, 0, 4, tmp);
+       /* restart autonegotiation */
+       tmp = mdio_read(card, 0, 0);
+       mdio_write(card, 0, 0, tmp | 0x1200);
+
+       if (rx)
+               activate_receiver(card);
+       if (tx)
+               activate_transmitter(card);     
+
+       leave();
+}
+
+
+/*
+  read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure.
+  This function will take the spinlock itself and can, as a result, not be called with the lock helt.
+ */
+static void read_mac_address(struct xircom_private *card)
+{
+       unsigned char j, tuple, link, data_id, data_count;
+       unsigned long flags;
+       int i;
+
+       enter();
+               
+       spin_lock_irqsave(&card->lock, flags);
+
+       outl(1 << 12, card->io_port + CSR9);    /* enable boot rom access */
+       for (i = 0x100; i < 0x1f7; i += link + 2) {
+               outl(i, card->io_port + CSR10);
+               tuple = inl(card->io_port + CSR9) & 0xff;
+               outl(i + 1, card->io_port + CSR10);
+               link = inl(card->io_port + CSR9) & 0xff;
+               outl(i + 2, card->io_port + CSR10);
+               data_id = inl(card->io_port + CSR9) & 0xff;
+               outl(i + 3, card->io_port + CSR10);
+               data_count = inl(card->io_port + CSR9) & 0xff;
+               if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) {
+                       /* 
+                        * This is it.  We have the data we want.
+                        */
+                       for (j = 0; j < 6; j++) {
+                               outl(i + j + 4, card->io_port + CSR10);
+                               card->dev->dev_addr[j] = inl(card->io_port + CSR9) & 0xff;
+                       }
+                       break;
+               } else if (link == 0) {
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+#ifdef DEBUG
+       for (i = 0; i < 6; i++)
+               printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
+       printk("\n");
+#endif
+       leave();
+}
+
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  It is just different enough from the EEPROM protocol
+   to not share code.  The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB       0x00000         /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN    0x40000
+#define MDIO_DATA_READ 0x80000
+
+static int mdio_read(struct xircom_private *card, int phy_id, int location)
+{
+       int i;
+       int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+       int retval = 0;
+       long mdio_addr = card->io_port + CSR9;
+
+       /* Establish sync by sending at least 32 logic ones. */
+       for (i = 32; i >= 0; i--) {
+               outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       /* Shift the read command bits out. */
+       for (i = 15; i >= 0; i--) {
+               int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+               outl(MDIO_ENB | dataval, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       /* Read the two transition, 16 data, and wire-idle bits. */
+       for (i = 19; i > 0; i--) {
+               outl(MDIO_ENB_IN, mdio_addr);
+               mdio_delay();
+               retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+               outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct xircom_private *card, int phy_id, int location, int value)
+{
+       int i;
+       int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+       long mdio_addr = card->io_port + CSR9;
+
+       /* Establish sync by sending 32 logic ones. */
+       for (i = 32; i >= 0; i--) {
+               outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       /* Shift the command bits out. */
+       for (i = 31; i >= 0; i--) {
+               int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+               outl(MDIO_ENB | dataval, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       /* Clear out extra bits. */
+       for (i = 2; i > 0; i--) {
+               outl(MDIO_ENB_IN, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+}
+
+
+/*
+ tranceiver_voodoo() enables the external UTP plug thingy.
+ it's called voodoo as I stole this code and cannot cross-reference
+ it with the specification.
+ */
+static void tranceiver_voodoo(struct xircom_private *card)
+{
+       unsigned long flags;
+       u32 tmp32;
+
+       enter();
+
+       /* disable all powermanagement */
+       pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32);
+       tmp32 &= ~PowerMgmtBits; 
+       pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32);
+
+       setup_descriptors(card);
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       outl(0x0008, card->io_port + CSR15);
+        udelay(25);  
+        outl(0xa8050000, card->io_port + CSR15);
+        udelay(25);
+        outl(0xa00f0000, card->io_port + CSR15);
+        udelay(25);
+        
+        spin_unlock_irqrestore(&card->lock, flags);
+
+       netif_start_queue(card->dev);
+       leave();
+}
+
+
+static void xircom_up(struct xircom_private *card)
+{
+       unsigned long flags;
+       int i;
+       u32 tmp32;
+
+       enter();
+
+       /* disable all powermanagement */
+       pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32);
+       tmp32 &= ~PowerMgmtBits; 
+       pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32);
+
+       setup_descriptors(card);
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       
+       enable_link_interrupt(card);
+       enable_transmit_interrupt(card);
+       enable_receive_interrupt(card);
+       enable_common_interrupts(card);
+       enable_promisc(card);
+       
+       /* The card can have received packets already, read them away now */
+       for (i=0;i<NUMDESCRIPTORS;i++) 
+               investigate_rx_descriptor(card->dev,card,i,bufferoffsets[i]);
+
+
+       set_half_duplex(card);
+       spin_unlock_irqrestore(&card->lock, flags);
+       trigger_receive(card);
+       trigger_transmit(card);
+       netif_start_queue(card->dev);
+       leave();
+}
+
+static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
+{
+               int status;             
+               
+               enter();
+               status = card->rx_desc[descnr].status;
+               
+               if ((status > 0)) {     /* packet received */
+               
+                       /* TODO: discard error packets */
+                       
+                       short pkt_len = ((status >> 16) & 0x7ff) - 4;   /* minus 4, we don't want the CRC */
+                       struct sk_buff *skb;
+
+                       if (pkt_len > 1518) {
+                               printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len);
+                               pkt_len = 1518;
+                       }
+
+                       skb = dev_alloc_skb(pkt_len + 2);
+                       if (skb == NULL) {
+                               card->stats.rx_dropped++;
+                               goto out;
+                       }
+                       skb->dev = dev;
+                       skb_reserve(skb, 2);
+                       eth_copy_and_sum(skb, &card->rx_buffer[bufferoffset], pkt_len, 0);
+                       skb_put(skb, pkt_len);
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_rx(skb);
+                       dev->last_rx = jiffies;
+                       card->stats.rx_packets++;
+                       card->stats.rx_bytes += pkt_len;
+                       
+                     out:
+                       /* give the buffer back to the card */
+                       card->rx_desc[descnr].status = DescOwnedCard;
+                       trigger_receive(card);
+               }
+
+               leave();
+
+}
+
+
+/* Returns 1 if the descriptor is free or became free */
+static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset)
+{
+               int status,retval = 0;
+               enter();
+               
+               status = card->tx_desc[descnr].status;
+               
+               if (status == DescOwnedDriver)
+                       return 1;
+#if 0          
+               if (status & 0x8000) {  /* Major error */
+                       printk(KERN_ERR "Major transmit error status %x \n", status);
+                       card->tx_desc[descnr].status = 0;
+                       netif_wake_queue (dev);
+               }
+#endif
+               if (status > 0) {       /* bit 31 is 0 when done */
+                       card->stats.tx_packets++;
+                       if (card->tx_skb[descnr]!=NULL) {
+                               card->stats.tx_bytes += card->tx_skb[descnr]->len;
+                               dev_kfree_skb_irq(card->tx_skb[descnr]);
+                       }
+                       card->tx_skb[descnr] = NULL;
+                       /* Bit 8 in the status field is 1 if there was a collision */
+                       if (status & CollisionBit)
+                               card->stats.collisions++;
+                       card->tx_desc[descnr].status = DescOwnedDriver; /* descriptor is free again */
+                       retval = 1;
+               }
+
+               leave();
+               return retval;          
+}
+
+
+static int __init xircom_init(void)
+{
+       pci_register_driver(&xircom_ops);
+       return 0;
+}
+
+static void __exit xircom_exit(void)
+{
+       pci_unregister_driver(&xircom_ops);
+} 
+
+module_init(xircom_init) 
+module_exit(xircom_exit)
index 1d90c05f25918597ddff4e3c237eda7cde26b6fb..6a90f5b5f1b5ad0ed358978680398774f68453f5 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
@@ -44,6 +44,7 @@
 #include <linux/ioport.h>
 #include <linux/config.h>
 #include <linux/pci.h>
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_PCI
 static struct pci_device_id card_ids[] = __devinitdata {
@@ -69,11 +70,12 @@ static struct pci_driver airo_driver = {
 
 /* Include Wireless Extension definition and check version - Jean II */
 #include <linux/wireless.h>
+#define WIRELESS_SPY           // enable iwspy support
 #if WIRELESS_EXT < 9
 #warning "Wireless extension v9 or newer required - please upgrade your kernel"
 #undef WIRELESS_EXT
+#undef WIRELESS_SPY
 #endif
-#define WIRELESS_SPY           // enable iwspy support
 #define CISCO_EXT              // enable Cisco extensions
 
 #ifdef CISCO_EXT
@@ -226,6 +228,7 @@ MODULE_AUTHOR("Benjamin Reed");
 MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
                    cards.  Direct support for ISA/PCI cards and support \
                   for PCMCIA when used with airo_cs.");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340");
 MODULE_PARM(io,"1-4i");
 MODULE_PARM(irq,"1-4i");
@@ -273,6 +276,7 @@ static int do8bitIO = 0;
 #define NOP 0x0010
 #define MAC_ENABLE 0x0001
 #define MAC_DISABLE 0x0002
+#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
 #define CMD_ACCESS 0x0021
 #define CMD_ALLOCATETX 0x000a
 #define CMD_TRANSMIT 0x000b
@@ -280,6 +284,7 @@ static int do8bitIO = 0;
 #define CMD_SETMODE 0x0009
 #define CMD_ENABLEAUX 0x0111
 #define CMD_SOFTRESET 0x0004
+#define CMD_LISTBSS 0x0103
 
 /* Registers */
 #define COMMAND 0x00
@@ -351,6 +356,22 @@ static int do8bitIO = 0;
 #define RID_STATS      0xFF68
 #define RID_STATSDELTA 0xFF69
 #define RID_STATSDELTACLEAR 0xFF6A
+#define RID_BSSLISTFIRST 0xFF72
+#define RID_BSSLISTNEXT  0xFF73
+
+typedef struct {
+       u16 cmd;
+       u16 parm0;
+       u16 parm1;
+       u16 parm2;
+} Cmd;
+
+typedef struct {
+       u16 status;
+       u16 rsp0;
+       u16 rsp1;
+       u16 rsp2;
+} Resp;
 
 /*
  * Rids and endian-ness:  The Rids will always be in cpu endian, since
@@ -358,6 +379,9 @@ static int do8bitIO = 0;
  * so all rid access should use the read/writeXXXRid routines.
  */
 
+/* This is redundant for x86 archs, but it seems necessary for ARM */
+#pragma pack(1)
+
 /* This structure came from an email sent to me from an engineer at
    aironet for inclusion into this driver */
 typedef struct {
@@ -387,20 +411,6 @@ typedef struct {
 #define MOD_MOK 2
 } ModulationRid;
 
-typedef struct {
-       u16 cmd;
-       u16 parm0;
-       u16 parm1;
-       u16 parm2;
-} Cmd;
-
-typedef struct {
-       u16 status;
-       u16 rsp0;
-       u16 rsp1;
-       u16 rsp2;
-} Resp;
-
 typedef struct {
        u16 len; /* sizeof(ConfigRid) */
        u16 opmode; /* operating mode */
@@ -496,7 +506,10 @@ typedef struct {
        u16 rssiThreshold;
 #define RSSI_DEFAULT 0
         u16 modulation;
-       u16 shortPreamble;
+#define PREAMBLE_AUTO 0
+#define PREAMBLE_LONG 1
+#define PREAMBLE_SHORT 2
+       u16 preamble;
        u16 homeProduct;
        u16 radioSpecific;
        /*---------- Aironet Extensions ----------*/
@@ -559,6 +572,7 @@ typedef struct {
 typedef struct {
        u16 len;
        char oui[3];
+       char zero;
        u16 prodNum;
        char manName[32];
        char prodName[16];
@@ -583,6 +597,38 @@ typedef struct {
        u16 requiredHard;
 } CapabilityRid;
 
+typedef struct {
+  u16 len;
+  u16 index; /* First is 0 and 0xffff means end of list */
+#define RADIO_FH 1 /* Frequency hopping radio type */
+#define RADIO_DS 2 /* Direct sequence radio type */
+#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
+  u16 radioType; 
+  u8 bssid[6]; /* Mac address of the BSS */
+  u8 zero;
+  u8 ssidLen;
+  u8 ssid[32];
+  u16 rssi;
+#define CAP_ESS (1<<0)
+#define CAP_IBSS (1<<1)
+#define CAP_PRIVACY (1<<4)
+#define CAP_SHORTHDR (1<<5)
+  u16 cap;
+  u16 beaconInterval;
+  u8 rates[8]; /* Same as rates for config rid */
+  struct { /* For frequency hopping only */
+    u16 dwell;
+    u8 hopSet;
+    u8 hopPattern;
+    u8 hopIndex;
+    u8 fill;
+  } fh;
+  u16 dsChannel;
+  u16 atimWindow;
+} BSSListRid;
+
+#pragma pack()
+
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
 #define TXCTL_TXEX (1<<2) /* report if tx fails */
 #define TXCTL_802_3 (0<<3) /* 802.3 packet */
@@ -661,7 +707,7 @@ typedef struct wep_key_t {
 } wep_key_t;
 #endif /* WIRELESS_EXT */
 
-static const char version[] = "airo.c 0.2 (Ben Reed & Javier Achirica)";
+static const char version[] = "airo.c 0.3 (Ben Reed & Javier Achirica)";
 
 struct airo_info;
 
@@ -749,6 +795,35 @@ static int setup_proc_entry( struct net_device *dev,
 static int takedown_proc_entry( struct net_device *dev,
                                struct airo_info *apriv );
 
+static int readBSSListRid(struct airo_info *ai, int first,
+                     BSSListRid *list) {
+       int rc;
+                       Cmd cmd;
+                       Resp rsp;
+
+       if (first == 1) {
+                       memset(&cmd, 0, sizeof(cmd));
+                       cmd.cmd=CMD_LISTBSS;
+                       issuecommand(ai, &cmd, &rsp);
+                       /* Let the command take effect */
+                       set_current_state (TASK_INTERRUPTIBLE);
+                       schedule_timeout (3*HZ);
+               }
+       rc = PC4500_readrid(ai, 
+                           first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
+                           list, sizeof(*list));
+
+       list->len = le16_to_cpu(list->len);
+       list->index = le16_to_cpu(list->index);
+       list->radioType = le16_to_cpu(list->radioType);
+       list->cap = le16_to_cpu(list->cap);
+       list->beaconInterval = le16_to_cpu(list->beaconInterval);
+       list->fh.dwell = le16_to_cpu(list->fh.dwell);
+       list->dsChannel = le16_to_cpu(list->dsChannel);
+       list->atimWindow = le16_to_cpu(list->atimWindow);
+       return rc;
+}
+
 static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) {
        int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, 
                                wkr, sizeof(*wkr));
@@ -918,7 +993,6 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        
        len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
        buffer = skb->data;
-       
        status = transmit_802_3_packet( priv, 
                                        fids[i],
                                        skb->data, len );
@@ -1167,7 +1241,6 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
        struct airo_info *apriv = (struct airo_info *)dev->priv;
        u16 savedInterrupts;
        
-
        if (!netif_device_present(dev))
                return;
        
@@ -1362,6 +1435,16 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
                        if(index!=-1)
                                apriv->stats.tx_bytes += len;
                } else {
+                       if (bap_setup(apriv, fid, 0x0004, BAP1) == SUCCESS) {
+                               u16 status;
+                               bap_read(apriv, &status, 2, BAP1);
+                               if (le16_to_cpu(status) & 2)
+                                       apriv->stats.tx_aborted_errors++;
+                               if (le16_to_cpu(status) & 4)
+                                       apriv->stats.tx_heartbeat_errors++;
+                               if (le16_to_cpu(status) & 0x10)
+                                       apriv->stats.tx_carrier_errors++;
+                       }
                        apriv->stats.tx_errors++;
                }
        }
@@ -1879,12 +1962,6 @@ static int transmit_802_3_packet(struct airo_info *ai, u16 txFid,
  *  like!  Feel free to clean it up!
  */
 
-/*
- *  Unfortunately sometime between 2.0 and 2.2 the proc interface changed...
- *  Unfortunately I dont know when it was...
- *  Im guessing it is sometime around 0x20155...  Anybody know?
- */
-
 static ssize_t proc_read( struct file *file,
                          char *buffer,
                          size_t len,
@@ -1901,6 +1978,7 @@ static int proc_statsdelta_open( struct inode *inode, struct file *file );
 static int proc_status_open( struct inode *inode, struct file *file );
 static int proc_SSID_open( struct inode *inode, struct file *file );
 static int proc_APList_open( struct inode *inode, struct file *file );
+static int proc_BSSList_open( struct inode *inode, struct file *file );
 static int proc_config_open( struct inode *inode, struct file *file );
 static int proc_wepkey_open( struct inode *inode, struct file *file );
 
@@ -1929,6 +2007,13 @@ static struct file_operations proc_SSID_ops = {
        release:       proc_close
 };
 
+static struct file_operations proc_BSSList_ops = {
+       read:          proc_read,
+       write:         proc_write,
+       open:          proc_BSSList_open,
+       release:       proc_close
+};
+
 static struct file_operations proc_APList_ops = {
        read:          proc_read,
        write:         proc_write,
@@ -1962,6 +2047,10 @@ struct proc_data {
        void (*on_close) (struct inode *, struct file *);
 };
 
+#ifndef SETPROC_OPS
+#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
+#endif
+
 static int setup_proc_entry( struct net_device *dev,
                             struct airo_info *apriv ) {
        struct proc_dir_entry *entry;
@@ -1979,11 +2068,7 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-/*     This is what was needed right up to the last few versions
-        of 2.3:
-       entry->ops = &proc_inode_statsdelta_ops;
-*/
-       entry->proc_fops = &proc_statsdelta_ops;
+       SETPROC_OPS(entry, proc_statsdelta_ops);
        
        /* Setup the Stats */
        entry = create_proc_entry("Stats",
@@ -1992,7 +2077,7 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-       entry->proc_fops = &proc_stats_ops;
+       SETPROC_OPS(entry, proc_stats_ops);
        
        /* Setup the Status */
        entry = create_proc_entry("Status",
@@ -2001,7 +2086,7 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-       entry->proc_fops = &proc_status_ops;
+       SETPROC_OPS(entry, proc_status_ops);
        
        /* Setup the Config */
        entry = create_proc_entry("Config",
@@ -2010,7 +2095,7 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-       entry->proc_fops = &proc_config_ops;
+       SETPROC_OPS(entry, proc_config_ops);
 
        /* Setup the SSID */
        entry = create_proc_entry("SSID",
@@ -2019,7 +2104,7 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-       entry->proc_fops = &proc_SSID_ops;
+       SETPROC_OPS(entry, proc_SSID_ops);
 
        /* Setup the APList */
        entry = create_proc_entry("APList",
@@ -2028,7 +2113,16 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-       entry->proc_fops = &proc_APList_ops;
+       SETPROC_OPS(entry, proc_APList_ops);
+
+       /* Setup the BSSList */
+       entry = create_proc_entry("BSSList",
+                                 S_IFREG | proc_perm,
+                                 apriv->proc_entry);
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
+       entry->data = dev;
+       SETPROC_OPS(entry, proc_BSSList_ops);
 
        /* Setup the WepKey */
        entry = create_proc_entry("WepKey",
@@ -2037,7 +2131,7 @@ static int setup_proc_entry( struct net_device *dev,
         entry->uid = proc_uid;
         entry->gid = proc_gid;
        entry->data = dev;
-       entry->proc_fops = &proc_wepkey_ops;
+       SETPROC_OPS(entry, proc_wepkey_ops);
 
        return 0;
 }
@@ -2051,6 +2145,7 @@ static int takedown_proc_entry( struct net_device *dev,
        remove_proc_entry("Config",apriv->proc_entry);
        remove_proc_entry("SSID",apriv->proc_entry);
        remove_proc_entry("APList",apriv->proc_entry);
+       remove_proc_entry("BSSList",apriv->proc_entry);
        remove_proc_entry("WepKey",apriv->proc_entry);
        remove_proc_entry(dev->name,airo_entry);
        return 0;
@@ -2124,6 +2219,7 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
        struct airo_info *apriv = (struct airo_info *)dev->priv;
        CapabilityRid cap_rid;
        StatusRid status_rid;
+       int i;
        
        MOD_INC_USE_COUNT;
        
@@ -2141,7 +2237,17 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
        readStatusRid(apriv, &status_rid);
        readCapabilityRid(apriv, &cap_rid);
        
-       sprintf( data->rbuffer, "Mode: %x\n"
+        i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
+                    status_rid.mode & 1 ? "CFG ": "",
+                    status_rid.mode & 2 ? "ACT ": "",
+                    status_rid.mode & 0x10 ? "SYN ": "",
+                    status_rid.mode & 0x20 ? "LNK ": "",
+                    status_rid.mode & 0x40 ? "LEAP ": "",
+                    status_rid.mode & 0x80 ? "PRIV ": "",
+                    status_rid.mode & 0x100 ? "KEY ": "",
+                    status_rid.mode & 0x200 ? "WEP ": "",
+                    status_rid.mode & 0x8000 ? "ERR ": "");
+       sprintf( data->rbuffer+i, "Mode: %x\n"
                 "Signal Strength: %d\n"
                 "Signal Quality: %d\n"
                 "SSID: %-.*s\n"
@@ -2425,6 +2531,14 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
                        default:
                                printk( KERN_WARNING "airo: Unknown modulation\n" );
                        }
+               } else if (!strncmp(line, "Preamble: ", 10)) {
+                       line += 10;
+                       switch(*line) {
+                       case 'a': config.preamble=PREAMBLE_AUTO; break;
+                       case 'l': config.preamble=PREAMBLE_LONG; break;
+                       case 's': config.preamble=PREAMBLE_SHORT; break;
+                       default: printk(KERN_WARNING "airo: Unknown preamble\n");
+                       }
                } else {
                        printk( KERN_WARNING "Couldn't figure out %s\n", line );
                }
@@ -2516,7 +2630,8 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
                 "RXDiversity: %s\n"
                 "FragThreshold: %d\n"
                 "WEP: %s\n"
-                "Modulation: %s\n",
+                "Modulation: %s\n"
+                "Preamble: %s\n",
                 (int)config.longRetryLimit,
                 (int)config.shortRetryLimit,
                 (int)config.rtsThres,
@@ -2531,7 +2646,10 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
                 config.authType == AUTH_SHAREDKEY ? "shared" : "open",
                 config.modulation == 0 ? "default" :
                 config.modulation == MOD_CCK ? "cck" :
-                config.modulation == MOD_MOK ? "mok" : "error"
+                config.modulation == MOD_MOK ? "mok" : "error",
+                config.preamble == PREAMBLE_AUTO ? "auto" :
+                config.preamble == PREAMBLE_LONG ? "long" :
+                config.preamble == PREAMBLE_SHORT ? "short" : "error"
                );
        data->readlen = strlen( data->rbuffer );
        return 0;
@@ -2862,6 +2980,76 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
        return 0;
 }
 
+static int proc_BSSList_open( struct inode *inode, struct file *file ) {
+       struct proc_data *data;
+       struct proc_dir_entry *dp = inode->u.generic_ip;
+       struct net_device *dev = dp->data;
+       struct airo_info *ai = (struct airo_info*)dev->priv;
+       char *ptr;
+       BSSListRid BSSList_rid;
+       int rc;
+       /* If doLoseSync is not 1, we won't do a Lose Sync */
+       int doLoseSync = -1;
+        
+       MOD_INC_USE_COUNT;
+       
+       dp = (struct proc_dir_entry *) inode->u.generic_ip;
+       
+       if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+               return -ENOMEM;
+       memset(file->private_data, 0, sizeof(struct proc_data));
+       data = (struct proc_data *)file->private_data;
+       if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
+               kfree (file->private_data);
+               return -ENOMEM;
+       }
+       data->writelen = 0;
+       data->maxwritelen = 0;
+       data->wbuffer = 0;
+       data->on_close = 0;
+       
+       if (file->f_mode & FMODE_WRITE) {
+               if (!(file->f_mode & FMODE_READ)) {
+                       Cmd cmd;
+                       Resp rsp;
+                        
+                       memset(&cmd, 0, sizeof(cmd));
+                       cmd.cmd=CMD_LISTBSS;
+                       issuecommand(ai, &cmd, &rsp);
+                       data->readlen = 0;
+                       return 0;
+               }
+               doLoseSync = 1;
+       }
+       ptr = data->rbuffer;
+       /* There is a race condition here if there are concurrent opens.
+           Since it is a rare condition, we'll just live with it, otherwise
+           we have to add a spin lock... */
+       rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
+       while(rc == 0 && BSSList_rid.index != 0xffff) {
+               ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
+                               (int)BSSList_rid.bssid[0],
+                               (int)BSSList_rid.bssid[1],
+                               (int)BSSList_rid.bssid[2],
+                               (int)BSSList_rid.bssid[3],
+                               (int)BSSList_rid.bssid[4],
+                               (int)BSSList_rid.bssid[5],
+                               (int)BSSList_rid.ssidLen,
+                               BSSList_rid.ssid,
+                               (int)BSSList_rid.rssi);
+               ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
+                               (int)BSSList_rid.dsChannel,
+                               BSSList_rid.cap & CAP_ESS ? "ESS" : "",
+                               BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
+                               BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
+                               BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
+               rc = readBSSListRid(ai, 0, &BSSList_rid);
+       }
+       *ptr = '\0';
+       data->readlen = strlen( data->rbuffer );
+       return 0;
+}
+
 static int proc_close( struct inode *inode, struct file *file ) 
 {
        struct proc_data *data = (struct proc_data *)file->private_data;
@@ -2971,7 +3159,6 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev)
 {
        stop_airo_card(pdev->driver_data, 1);
 }
-
 #endif
 
 static int __init airo_init_module( void )
@@ -3041,14 +3228,13 @@ static void __exit airo_cleanup_module( void )
  */
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       int rc = 0;
+       int i, rc = 0;
 #ifdef WIRELESS_EXT
        struct airo_info *local = (struct airo_info*) dev->priv;
        struct iwreq *wrq = (struct iwreq *) rq;
        ConfigRid config;               /* Configuration info */
        CapabilityRid cap_rid;          /* Card capability info */
        StatusRid status_rid;           /* Card status info */
-       int i;
 
 #ifdef CISCO_EXT
        if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC)
@@ -3557,31 +3743,50 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 #endif /* WIRELESS_EXT > 9 */
 
 #if WIRELESS_EXT > 10
-       case SIOCGIWRETRY:
-               wrq->u.retry.disabled = 0;
-               if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
-                       wrq->u.retry.value = (int)config.txLifetime * 1024;
-               else {
-                       wrq->u.retry.value = (int)config.shortRetryLimit;
-                       wrq->u.retry.flags = IW_RETRY_LIMIT;
-               }
-               break;
-
-       case SIOCSIWRETRY: 
-               if (wrq->u.retry.disabled) {
-                       config.shortRetryLimit = 0;
-                       config.longRetryLimit = 0;
-                       config.txLifetime = 0;
-                       local->need_commit = 1;
+       case SIOCSIWRETRY:
+               if(wrq->u.retry.disabled) {
+                       rc = -EINVAL;
                        break;
                }
-               if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-                       config.txLifetime = (wrq->u.retry.value + 500) / 1024;
+               local->need_commit = 0;
+               if(wrq->u.retry.flags & IW_RETRY_LIMIT) {
+                       if(wrq->u.retry.flags & IW_RETRY_MAX)
+                               config.longRetryLimit = wrq->u.retry.value;
+                       else if (wrq->u.retry.flags & IW_RETRY_MIN)
+                               config.shortRetryLimit = wrq->u.retry.value;
+                       else {
+                               /* No modifier : set both */
+                               config.longRetryLimit = wrq->u.retry.value;
+                               config.shortRetryLimit = wrq->u.retry.value;
+                       }
                        local->need_commit = 1;
-               } else if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIMIT) {
-                       config.shortRetryLimit = config.longRetryLimit = wrq->u.retry.value;
+               }
+               if(wrq->u.retry.flags & IW_RETRY_LIFETIME) {
+                       config.txLifetime = wrq->u.retry.value / 1024;
                        local->need_commit = 1;
                }
+               if(local->need_commit == 0) {
+                       rc = -EINVAL;
+               }
+               break;
+
+       case SIOCGIWRETRY:
+               wrq->u.retry.disabled = 0;      /* Can't be disabled */
+
+               /* Note : by default, display the min retry number */
+               if((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+                       wrq->u.retry.flags = IW_RETRY_LIFETIME;
+                       wrq->u.retry.value = (int)config.txLifetime * 1024;
+               } else if((wrq->u.retry.flags & IW_RETRY_MAX)) {
+                       wrq->u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+                       wrq->u.retry.value = (int)config.longRetryLimit;
+               } else {
+                       wrq->u.retry.flags = IW_RETRY_LIMIT;
+                       wrq->u.retry.value = (int)config.shortRetryLimit;
+                       if((int)config.shortRetryLimit != (int)config.longRetryLimit)
+                               wrq->u.retry.flags |= IW_RETRY_MIN;
+               }
+
                break;
 #endif /* WIRELESS_EXT > 10 */
 
@@ -3593,8 +3798,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                        int             k;
 
                        wrq->u.data.length = sizeof(range);
-                       /* Should adapt depending on max rate */
-                       range.throughput = 1.6 * 1024 * 1024;
+                       memset(&range, 0, sizeof(range));
                        range.min_nwid = 0x0000;
                        range.max_nwid = 0x0000;
                        range.num_channels = 14;
@@ -3621,6 +3825,14 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                        }
                        range.num_bitrates = i;
 
+                       /* Set an indication of the max TCP throughput
+                        * in bit/s that we can expect using this interface.
+                        * May be use for QoS stuff... Jean II */
+                       if(i > 2)
+                               range.throughput = 5 * 1000 * 1000;
+                       else
+                               range.throughput = 1.5 * 1000 * 1000;
+
                        range.min_rts = 0;
                        range.max_rts = 2312;
                        range.min_frag = 256;
@@ -3753,15 +3965,53 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
        case SIOCGIWAPLIST:
                if (wrq->u.data.pointer) {
-                       int i;
-                       struct sockaddr s[4];
-
-                       for (i = 0; i < 4; i++) {
-                               memcpy(s[i].sa_data, status_rid.bssid[i], 6);
+                       int i, rc;
+                       struct sockaddr s[IW_MAX_AP];
+                       struct iw_quality qual[IW_MAX_AP];
+                       BSSListRid BSSList;
+                       int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
+                       for (i = 0; i < IW_MAX_AP; i++) {
+                               if (readBSSListRid(local, loseSync, &BSSList))
+                                       break;
+                               loseSync = 0;
+                               memcpy(s[i].sa_data, BSSList.bssid, 6);
                                s[i].sa_family = ARPHRD_ETHER;
+                               qual[i].level = BSSList.rssi;
+                               qual[i].qual = qual[i].noise = 0;
+                               qual[i].updated = 2;
+                               if (BSSList.index == 0xffff) break;
+                       }
+                       if (!i) {
+                               for (i = 0; 
+                                    i < min(IW_MAX_AP, 4) &&
+                                            (status_rid.bssid[i][0]
+                                             & status_rid.bssid[i][1]
+                                             & status_rid.bssid[i][2]
+                                             & status_rid.bssid[i][3]
+                                             & status_rid.bssid[i][4]
+                                             & status_rid.bssid[i][5])!=-1 &&
+                                            (status_rid.bssid[i][0]
+                                             | status_rid.bssid[i][1]
+                                             | status_rid.bssid[i][2]
+                                             | status_rid.bssid[i][3]
+                                             | status_rid.bssid[i][4]
+                                             | status_rid.bssid[i][5]);
+                                    i++) {
+                                       memcpy(s[i].sa_data, 
+                                              status_rid.bssid[i], 6);
+                                       s[i].sa_family = ARPHRD_ETHER;
+                               }
+                       } else {
+                               wrq->u.data.flags = 1; /* Should be define'd */
+                               if (copy_to_user(wrq->u.data.pointer
+                                                + sizeof(struct sockaddr)*i,
+                                                &qual,
+                                                sizeof(struct iw_quality)*i))
+                                       rc = -EFAULT;
                        }
-                       wrq->u.data.length = 4;
-                       if (copy_to_user(wrq->u.data.pointer, &s, sizeof(s)))
+                       wrq->u.data.length = i;
+                       if (copy_to_user(wrq->u.data.pointer, &s, 
+                                        sizeof(struct sockaddr)*i))
                                rc = -EFAULT;
                }
                break;
index c6a684b7a57968c9974c490ff9b43dd16edd3d03..3c567682930ccdaa49aea467f724743d6e39e117 100644 (file)
 
 #include "hermes.h"
 
-static const char version[] __initdata = "hermes.c: 1 Aug 2001 David Gibson <hermes@gibson.dropbear.id.au>";
+static char version[] __initdata = "hermes.c: 1 Aug 2001 David Gibson <hermes@gibson.dropbear.id.au>";
 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_LICENSE("GPL");
 
 /* These are maximum timeouts. Most often, card wil react much faster */
 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
@@ -40,7 +41,6 @@ MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
 #define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
-#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */
 
 #define MAX(a, b) ( (a) > (b) ? (a) : (b) )
 #define MIN(a, b) ( (a) < (b) ? (a) : (b) )
@@ -65,12 +65,6 @@ MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 
 #endif /* ! HERMES_DEBUG */
 
-/*
- * Prototypes
- */
-
-static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0);
-
 /*
  * Internal functions
  */
@@ -303,7 +297,6 @@ static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
        int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
        int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
        int k;
-       int l = BAP_ERROR_RETRY;
        uint16_t reg;
 
        /* Paranoia.. */
@@ -317,7 +310,6 @@ static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
                return -EBUSY;
 
        /* Now we actually set up the transfer */
- retry:
        hermes_write_reg(hw, sreg, id);
        hermes_write_reg(hw, oreg, offset);
 
@@ -331,20 +323,16 @@ static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
        }
 
        if (reg & HERMES_OFFSET_BUSY) {
-               DEBUG(0,"hermes_bap_seek: returning ETIMEDOUT...\n");
+               DEBUG(1,"hermes_bap_seek: timeout\n");
                return -ETIMEDOUT;
        }
 
-       /* For some reason, seeking the BAP seems to randomly fail somewhere
-          (firmware bug?). We retry a few times before giving up. */
        if (reg & HERMES_OFFSET_ERR) {
-               if (l--) {
-                       udelay(1);
-                       goto retry;
-               } else
-                       return -EIO;
+               DEBUG(1,"hermes_bap_seek: BAP error\n");
+               return -EIO;
        }
 
+
        return 0;
 }
 
index bc74036f247c793d335213e9319c83ae859aea4f..58c663331b5b904c92b454a7935d6656665dfceb 100644 (file)
  * Frame structures and constants
  */
 
+#define __PACKED__ __attribute__ ((packed))
+
 typedef struct hermes_frame_desc {
        /* Hermes - i.e. little-endian byte-order */
-       uint16_t status; /* 0x0 */
-       uint16_t res1, res2; /* 0x2, 0x4 */
-       uint16_t q_info; /* 0x6 */
-       uint16_t res3, res4; /* 0x8, 0xA */
-       uint16_t tx_ctl; /* 0xC */
-} __attribute__ ((packed)) hermes_frame_desc_t;
+       uint16_t status __PACKED__;
+       uint16_t res1, res2 __PACKED__;
+       uint16_t q_info __PACKED__;
+       uint16_t res3, res4 __PACKED__;
+       uint16_t tx_ctl __PACKED__;
+} hermes_frame_desc_t;
 
 #define                HERMES_RXSTAT_ERR               (0x0003)
 #define                HERMES_RXSTAT_MACPORT           (0x0700)
@@ -246,21 +248,12 @@ typedef struct hermes_response {
        uint16_t status, resp0, resp1, resp2;
 } hermes_response_t;
 
-/* Firmware information structure */
-typedef struct hermes_identity {
-       uint16_t id, vendor, major, minor;
-} __attribute__ ((packed)) hermes_identity_t;
-
 /* "ID" structure - used for ESSID and station nickname */
 typedef struct hermes_id {
        uint16_t len;
        uint16_t val[16];
 } __attribute__ ((packed)) hermes_id_t;
 
-typedef struct hermes_commsqual {
-       uint16_t qual, signal, noise;
-} __attribute__ ((packed)) hermes_commsqual_t;
-
 typedef struct hermes_multicast {
        uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN];
 } __attribute__ ((packed)) hermes_multicast_t;
@@ -351,37 +344,6 @@ static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint
        return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
 }
 
-static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf)
-{
-       int err;
-
-       err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf);
-       if (err)
-               return err;
-
-       le16_to_cpus(&buf->id);
-       le16_to_cpus(&buf->vendor);
-       le16_to_cpus(&buf->major);
-       le16_to_cpus(&buf->minor);
-       
-       return 0;
-}
-
-static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf)
-{
-       int err;
-
-       err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf);
-       if (err)
-               return err;
-
-       le16_to_cpus(&buf->qual);
-       le16_to_cpus(&buf->signal);
-       le16_to_cpus(&buf->noise);
-       
-       return 0;
-}
-
 #else /* ! __KERNEL__ */
 
 /* These are provided for the benefit of userspace drivers and testing programs
index 2560a38c884d31a3b1c4de10240e8ce7c307b56a..777faa3e56b89b814ace88232600d6350cc0188c 100644 (file)
@@ -1,4 +1,4 @@
-/* orinoco.c 0.06f     - (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.0     - (formerly known as dldwd_cs.c and orinoco_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
  *       00:00:00.  We really need a better way of handling this, but the module flag
  *       is better than nothing for now.
  *
+ * v0.06f -> v0.07 - 20/8/2001 - David Gibson
+ *     o Removed BAP error retries from hermes_bap_seek().  For Tx we now
+ *       let the upper layers handle the retry, we retry explicitly in the
+ *       Rx path, but don't make as much noise about it.
+ *     o Firmware detection cleanups.
+ *
+ *
  * TODO - Jean II
  *     o inline functions (lot's of candidate, need to reorder code)
  *     o Test PrismII/Symbol cards & firmware versions
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include "hermes.h"
 #include "orinoco.h"
 
-static const char version[] __initdata = "orinoco.c 0.06f (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
+MODULE_LICENSE("Dual MPL/GPL");
 
 /* Level of debugging. Used in the macros in orinoco.h */
 #ifdef ORINOCO_DEBUG
@@ -276,20 +284,22 @@ struct p80211_hdr {
 #define DLDWD_FTYPE_CTL                        0x0004
 #define DLDWD_FTYPE_DATA               0x0008
 
+#define __PACKED__ __attribute__ ((packed))
+
 struct p8022_hdr {
-       uint8_t dsap;
-       uint8_t ssap;
-       uint8_t ctrl;
-       uint8_t oui[3];
-} __attribute__ ((packed));
+       uint8_t dsap __PACKED__;
+       uint8_t ssap __PACKED__;
+       uint8_t ctrl __PACKED__;
+       uint8_t oui[3] __PACKED__;
+};
 
 struct dldwd_frame_hdr {
-       hermes_frame_desc_t desc;
-       struct p80211_hdr p80211;
-       struct ethhdr p8023;
-       struct p8022_hdr p8022;
-       uint16_t ethertype;
-} __attribute__ ((packed));
+       hermes_frame_desc_t desc __PACKED__;
+       struct p80211_hdr p80211 __PACKED__;
+       struct ethhdr p8023 __PACKED__;
+       struct p8022_hdr p8022 __PACKED__;
+       uint16_t ethertype __PACKED__;
+};
 
 #define P8023_OFFSET           (sizeof(hermes_frame_desc_t) + \
                                sizeof(struct p80211_hdr))
@@ -303,6 +313,14 @@ struct p8022_hdr alternate_encaps_hdr = {
        0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}
 };
 
+/* How many times to retry if we get an EIO reading the BAP in the Rx path */
+#define RX_EIO_RETRY           10
+
+typedef struct dldwd_commsqual {
+       uint16_t qual, signal, noise;
+} __PACKED__ dldwd_commsqual_t;
+
+
 /*
  * Function prototypes
  */
@@ -419,11 +437,6 @@ set_port_type(dldwd_priv_t *priv)
                        priv->port_type = 3;
                        priv->allow_ibss = 0;
                } else {
-                       /* Symbol is different here */
-                       if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-                               priv->port_type = 4;
-                       else
-                               priv->port_type = 1;
                        priv->port_type = priv->ibss_port;
                        priv->allow_ibss = 1;
                }
@@ -673,7 +686,7 @@ static int __dldwd_hw_setup_wep(dldwd_priv_t *priv)
                        return err;
                break;
 
-       case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */
+       case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
        case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
                master_wep_flag = 0;            /* Off */
                if (priv->wep_on) {
@@ -703,7 +716,7 @@ static int __dldwd_hw_setup_wep(dldwd_priv_t *priv)
                        if (err)
                                return err;
 
-                       /* Authentication is where Prism2 and Symbol
+                       /* Authentication is where Intersil and Symbol
                         * firmware differ... */
                        if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
                                /* Symbol cards : set the authentication :
@@ -877,7 +890,7 @@ static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
        return 0;
 }
 
-#ifndef PCMCIA_DEBUG
+#ifndef ORINOCO_DEBUG
 static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {}
 #else
 static void show_rx_frame(struct dldwd_frame_hdr *frame)
@@ -1052,6 +1065,7 @@ static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
        struct net_device_stats *stats = &priv->stats;
        struct iw_statistics *wstats = &priv->wstats;
        struct sk_buff *skb = NULL;
+       int l = RX_EIO_RETRY;
        uint16_t rxfid, status;
        int length, data_len, data_off;
        char *p;
@@ -1066,13 +1080,20 @@ static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
           necessary, since we ignore most of it, but it's
           conceptually simpler. We can tune this later if
           necessary. */
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0);
+       do {
+               err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
+                                      rxfid, 0);
+       } while ( (err == -EIO) && (--l) );
        if (err) {
-               printk(KERN_ERR "%s: error %d reading frame header. "
-                      "Frame dropped.\n", dev->name, err);
+               if (err == -EIO)
+                       DEBUG(1, "%s: EIO reading frame header.\n", dev->name);
+               else
+                       printk(KERN_ERR "%s: error %d reading frame header. "
+                              "Frame dropped.\n", dev->name, err);
                stats->rx_errors++;
                goto drop;
        }
+       DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l);
 
        status = le16_to_cpu(hdr.desc.status);
        
@@ -1138,8 +1159,7 @@ static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
           (!memcmp(&hdr.p8022, &encaps_hdr, 3))) {
                /* These indicate a SNAP within 802.2 LLC within
                   802.11 frame which we'll need to de-encapsulate to
-                  the original EthernetII frame.
-                  IEEE and ISO OSI have a lot to answer for.  */
+                  the original EthernetII frame. */
 
                /* Remove SNAP header, reconstruct EthernetII frame */
                data_len = length - ENCAPS_OVERHEAD;
@@ -1161,13 +1181,20 @@ static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
        }
 
        p = skb_put(skb, data_len);
-       if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
-                            rxfid, data_off) != 0) {
-               printk(KERN_WARNING "%s: Error reading packet data\n",
-                      dev->name);
+       do {
+               err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
+                                      rxfid, data_off);
+       } while ( (err == -EIO) && (--l) );
+       if (err) {
+               if (err == -EIO)
+                       DEBUG(1, "%s: EIO reading frame header.\n", dev->name);
+               else
+                       printk(KERN_ERR "%s: error %d reading frame header. "
+                              "Frame dropped.\n", dev->name, err);
                stats->rx_errors++;
                goto drop;
        }
+       DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l);
 
        dev->last_rx = jiffies;
        skb->dev = dev;
@@ -1231,28 +1258,38 @@ static void determine_firmware(struct net_device *dev)
        dldwd_priv_t *priv = dev->priv;
        hermes_t *hw = &priv->hw;
        int err;
+       struct sta_id {
+               uint16_t id, vendor, major, minor;
+       } __PACKED__ sta_id;
        uint32_t firmver;
-       char *vendor_str;
 
        /* Get the firmware version */
-       err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info);
+       err = HERMES_READ_RECORD(hw, USER_BAP,
+                                HERMES_RID_STAIDENTITY, &sta_id);
        if (err) {
                printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
                       dev->name, err);
-               memset(&priv->firmware_info, 0, sizeof(priv->firmware_info));
+               memset(&sta_id, 0, sizeof(sta_id));
        }
+       le16_to_cpus(&sta_id.id);
+       le16_to_cpus(&sta_id.vendor);
+       le16_to_cpus(&sta_id.major);
+       le16_to_cpus(&sta_id.minor);
 
-       firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor;
-       DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver);
+       firmver = ((uint32_t)sta_id.major << 16) | sta_id.minor;
+
+       printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
+              dev->name, sta_id.id, sta_id.vendor,
+              sta_id.major, sta_id.minor);
 
        /* Determine capabilities from the firmware version */
 
-       switch (priv->firmware_info.vendor) {
-       case 0x1:
+       if (sta_id.vendor == 1) {
                /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
-                * ELSA, Melco, HP, IBM, Dell 1150 cards */
-               vendor_str = "Lucent";
-               /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */
+                  ELSE, Meloc, HP, IBM, Dell 1150 */
+               printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware "
+                      "version %d.%02d\n", dev->name,
+                      sta_id.major, sta_id.minor);
 
                priv->firmware_type = FIRMWARE_TYPE_LUCENT;
                priv->tx_rate_ctrl = 0x3;       /* 11 Mb/s auto */
@@ -1268,118 +1305,62 @@ static void determine_firmware(struct net_device *dev)
                priv->has_mwo = (firmver >= 0x60000);
                priv->has_pm = (firmver >= 0x40020);
                priv->has_preamble = 0;
+               priv->ibss_port = 1;
                /* Tested with Lucent firmware :
                 *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
                 * Tested CableTron firmware : 4.32 => Anton */
-               break;
-       case 0x2:
-               vendor_str = "Generic Prism II";
-               /* Some D-Link cards report vendor 0x02... */
-
-               priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+       } else if ((sta_id.vendor == 2) &&
+                  ((firmver == 0x10001) || (firmver == 0x20001))) {
+               /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+               /* Intel MAC : 00:02:B3:* */
+               /* 3Com MAC : 00:50:DA:* */
+               printk(KERN_DEBUG "%s: Looks like a Symbol firmware "
+                      "(unknown version)\n", dev->name);
+
+               /* FIXME : we need to get Symbol firmware revision.
+                * I tried to use SYMBOL_***ARY_VER, but it didn't
+                * returned anything proper... */
+               priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
                priv->tx_rate_ctrl = 0xF;       /* 11 Mb/s auto */
-               priv->need_card_reset = 0;
+               priv->need_card_reset = 1;
                priv->broken_reset = 0;
-               priv->broken_allocate = 0;
-               priv->has_port3 = 1;
-               priv->has_ibss = (firmver >= 0x00007); /* FIXME */
-               priv->has_wep = (firmver >= 0x00007); /* FIXME */
-               priv->has_big_wep = 0;
-               priv->has_mwo = 0;
-               priv->has_pm = (firmver >= 0x00007); /* FIXME */
-               priv->has_preamble = 0;
-
-               /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */
-
-               /* Special case for Symbol cards */
-               if(firmver == 0x10001) {
-                       /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
-                       vendor_str = "Symbol";
-                       /* Intel MAC : 00:02:B3:* */
-                       /* 3Com MAC : 00:50:DA:* */
-
-                       /* FIXME : we need to get Symbol firmware revision.
-                        * I tried to use SYMBOL_***ARY_VER, but it didn't
-                        * returned anything proper... */
-                       priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
-                       priv->tx_rate_ctrl = 0xF;       /* 11 Mb/s auto */
-                       priv->need_card_reset = 1;
-                       priv->broken_reset = 0;
-                       priv->broken_allocate = 1;
-                       priv->has_port3 = 1;
-                       priv->has_ibss = 1; /* FIXME */
-                       priv->has_wep = 1; /* FIXME */
-                       priv->has_big_wep = 1;  /* RID_SYMBOL_KEY_LENGTH */
-                       priv->has_mwo = 0;
-                       priv->has_pm = 1; /* FIXME */
-                       priv->has_preamble = 0; /* FIXME */
-                       /* Tested with Intel firmware : v15 => Jean II */
-               }
-               break;
-       case 0x3:
-               vendor_str = "Samsung";
-               /* To check - Should cover Samsung & Compaq */
-
-               priv->firmware_type = FIRMWARE_TYPE_PRISM2;
-               priv->tx_rate_ctrl = 0xF;       /* 11 Mb/s auto */
-               priv->need_card_reset = 0;
-               priv->broken_reset = 0;
-               priv->broken_allocate = 0;
+               priv->broken_allocate = 1;
                priv->has_port3 = 1;
-               priv->has_ibss = 0; /* FIXME: available in later firmwares */
-               priv->has_wep = (firmver >= 0x20000); /* FIXME */
-               priv->has_big_wep = 0; /* FIXME */
+               priv->has_ibss = 1; /* FIXME */
+               priv->has_wep = 1; /* FIXME */
+               priv->has_big_wep = 1;  /* RID_SYMBOL_KEY_LENGTH */
                priv->has_mwo = 0;
-               priv->has_pm = (firmver >= 0x20000); /* FIXME */
-               priv->has_preamble = 0;
-               break;
-       case 0x6:
-               /* D-Link DWL 650, ... */
-               vendor_str = "LinkSys/D-Link";
-               /* D-Link MAC : 00:40:05:* */
+               priv->has_pm = 1; /* FIXME */
+               priv->has_preamble = 0; /* FIXME */
+               priv->ibss_port = 4;
+               /* Tested with Intel firmware : v15 => Jean II */
+       } else {
+               printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
+                      "version %d.%02d\n", dev->name,
+                      sta_id.major, sta_id.minor);
 
-               priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+               priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
                priv->tx_rate_ctrl = 0xF;       /* 11 Mb/s auto */
                priv->need_card_reset = 0;
                priv->broken_reset = 0;
                priv->broken_allocate = 0;
                priv->has_port3 = 1;
                priv->has_ibss = (firmver >= 0x00007); /* FIXME */
-               priv->has_wep = (firmver >= 0x00007); /* FIXME */
+               priv->has_wep = (firmver >= 0x00008);
                priv->has_big_wep = 0;
                priv->has_mwo = 0;
-               priv->has_pm = (firmver >= 0x00007); /* FIXME */
+               priv->has_pm = (firmver >= 0x00007);
                priv->has_preamble = 0;
-               /* Tested with D-Link firmware 0.07 => Jean II */
-               /* Note : with 0.07, IBSS to a Lucent card seem flaky */
-               break;
-       default:
-               vendor_str = "UNKNOWN";
 
-               priv->firmware_type = 0;
-               priv->tx_rate_ctrl = 0x3;               /* Hum... */
-               priv->need_card_reset = 0;
-               priv->broken_reset = 0;
-               priv->broken_allocate = 0;
-               priv->has_port3 = 0;
-               priv->has_ibss = 0;
-               priv->has_wep = 0;
-               priv->has_big_wep = 0;
-               priv->has_mwo = 0;
-               priv->has_pm = 0;
-               priv->has_preamble = 0;
+               if (firmver >= 0x00008)
+                       priv->ibss_port = 0;
+               else {
+                       printk(KERN_NOTICE "%s: Intersil firmware earlier "
+                              "than v0.08 - several features not supported.",
+                              dev->name);
+                       priv->ibss_port = 1;
+               }
        }
-       
-       if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-               priv->ibss_port = 4;
-       else if ( (priv->firmware_type == FIRMWARE_TYPE_PRISM2) && (firmver >= 0x00008) )
-               priv->ibss_port = 0;
-       else
-               priv->ibss_port = 1;
-
-       printk(KERN_DEBUG "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n",
-              dev->name, priv->firmware_info.id, priv->firmware_info.vendor,
-              vendor_str, priv->firmware_info.major, priv->firmware_info.minor);
 }
 
 /*
@@ -1551,7 +1532,6 @@ dldwd_get_wireless_stats(struct net_device *dev)
        hermes_t *hw = &priv->hw;
        struct iw_statistics *wstats = &priv->wstats;
        int err = 0;
-       hermes_commsqual_t cq;
 
        if (!priv->hw_ready)
                return NULL;
@@ -1571,7 +1551,14 @@ dldwd_get_wireless_stats(struct net_device *dev)
                }
 #endif /* WIRELESS_SPY */
        } else {
-               err = hermes_read_commsqual(hw, USER_BAP, &cq);
+               dldwd_commsqual_t cq;
+
+               err = HERMES_READ_RECORD(hw, USER_BAP,
+                                        HERMES_RID_COMMSQUALITY, &cq);
+               
+               le16_to_cpus(&cq.qual);
+               le16_to_cpus(&cq.signal);
+               le16_to_cpus(&cq.noise);
                
                DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name,
                      cq.qual, cq.signal, cq.noise);
@@ -1597,7 +1584,7 @@ dldwd_get_wireless_stats(struct net_device *dev)
 #ifdef WIRELESS_SPY
 static inline void dldwd_spy_gather(struct net_device *dev,
                                    u_char *mac,
-                                   hermes_commsqual_t *cq)
+                                   dldwd_commsqual_t *cq)
 {
        dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
        int i;
@@ -1620,7 +1607,7 @@ dldwd_stat_gather( struct net_device *dev,
                   struct dldwd_frame_hdr *hdr)
 {
        dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-       hermes_commsqual_t cq;
+       dldwd_commsqual_t cq;
 
        /* Using spy support with lots of Rx packets, like in an
         * infrastructure (AP), will really slow down everything, because
@@ -1722,9 +1709,15 @@ dldwd_xmit(struct sk_buff *skb, struct net_device *dev)
                err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
                                         txfid, 0);
                if (err) {
-                       printk(KERN_ERR
-                              "%s: Error %d writing packet header to BAP\n",
-                              dev->name, err);
+                       if (err == -EIO)
+                               /* We get these errors reported by the
+                                  firmware every so often apparently at
+                                  random.  Let the upper layers
+                                  handle the retry */
+                               DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name);
+                       else
+                               printk(KERN_ERR "%s: Error %d writing packet header to BAP\n",
+                                      dev->name, err);
                        stats->tx_errors++;
                        goto fail;
                }
@@ -1749,12 +1742,14 @@ dldwd_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Round up for odd length packets */
        err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off);
        if (err) {
-               printk(KERN_ERR "%s: Error %d writing packet data to BAP\n",
-                      dev->name, err);
+               if (err == -EIO)
+                       DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name);
+               else
+                       printk(KERN_ERR "%s: Error %d writing packet header to BAP",
+                              dev->name, err);
                stats->tx_errors++;
                goto fail;
        }
-       
 
        /* Finally, we actually initiate the send */
        err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp);
@@ -1941,7 +1936,9 @@ static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
 
        if (erq->pointer) {
                /* We actually have a key to set */
-               
+               if(erq->length > MAX_KEY_SIZE)
+                       return -EINVAL;
+
                if (copy_from_user(keybuf, erq->pointer, erq->length))
                        return -EFAULT;
        }
@@ -2344,7 +2341,7 @@ static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
                else
                        priv->tx_rate_ctrl = rate_ctrl;
                break;
-       case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */
+       case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
        case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
                switch(brate) {
                case 0:
@@ -2418,7 +2415,7 @@ static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
                } else
                        rrq->fixed = 1;
                break;
-       case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */
+       case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
        case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
                /* Check if auto or fixed (crude approximation) */
                if((val & 0x1) && (val > 1)) {
@@ -3649,32 +3646,32 @@ dldwd_proc_cleanup(void)
 int
 dldwd_setup(dldwd_priv_t* priv)
 {
-       struct net_device *ndev = &priv->ndev;;
+       struct net_device *dev = &priv->ndev;;
 
        spin_lock_init(&priv->lock);
 
        /* Set up the net_device */
-       ether_setup(ndev);
-       ndev->priv = priv;
+       ether_setup(dev);
+       dev->priv = priv;
 
        /* Setup up default routines */
        priv->card_reset_handler = NULL;        /* Caller may override */
-       ndev->init = dldwd_init;
-       ndev->open = NULL;              /* Caller *must* override */
-       ndev->stop = NULL;
-       ndev->hard_start_xmit = dldwd_xmit;
-       ndev->tx_timeout = dldwd_tx_timeout;
-       ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */
+       dev->init = dldwd_init;
+       dev->open = NULL;               /* Caller *must* override */
+       dev->stop = NULL;
+       dev->hard_start_xmit = dldwd_xmit;
+       dev->tx_timeout = dldwd_tx_timeout;
+       dev->watchdog_timeo = HZ; /* 4 second timeout */
 
-       ndev->get_stats = dldwd_get_stats;
-       ndev->get_wireless_stats = dldwd_get_wireless_stats;
+       dev->get_stats = dldwd_get_stats;
+       dev->get_wireless_stats = dldwd_get_wireless_stats;
 
-       ndev->do_ioctl = dldwd_ioctl;
+       dev->do_ioctl = dldwd_ioctl;
 
-       ndev->change_mtu = dldwd_change_mtu;
-       ndev->set_multicast_list = dldwd_set_multicast_list;
+       dev->change_mtu = dldwd_change_mtu;
+       dev->set_multicast_list = dldwd_set_multicast_list;
 
-       netif_stop_queue(ndev);
+       netif_stop_queue(dev);
 
        return 0;
 }
index db2b6638cc4a96e3d8959dcbbcaad7e88921db42..07d94110e4867b601e3c4987639f843578189165 100644 (file)
@@ -64,10 +64,9 @@ typedef struct dldwd_priv {
        uint16_t txfid;
 
        /* Capabilities of the hardware/firmware */
-       hermes_identity_t firmware_info;
        int firmware_type;
 #define FIRMWARE_TYPE_LUCENT 1
-#define FIRMWARE_TYPE_PRISM2 2
+#define FIRMWARE_TYPE_INTERSIL 2
 #define FIRMWARE_TYPE_SYMBOL 3
        int has_ibss, has_port3, prefer_port3, has_ibss_any, ibss_port;
        int has_wep, has_big_wep;
@@ -143,5 +142,4 @@ extern int dldwd_proc_dev_init(dldwd_priv_t *dev);
 extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv);
 extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs);
 
-
 #endif
index 2a26a07c4c1c147f708e106923ea8ea431c0e905..651ee6c81925669dcc082fc309de2172aa9f0429 100644 (file)
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.06f  - (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.0  - (formerly known as dldwd_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
 
 /*====================================================================*/
 
-static const char version[] __initdata = "orinoco_cs.c 0.06f (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco_cs.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards");
+MODULE_LICENSE("Dual MPL/GPL");
 
 /* Parameters that can be set with 'insmod' */
 
@@ -181,7 +182,7 @@ dldwd_cs_cor_reset(dldwd_priv_t *priv)
        dldwd_card_t* card = (dldwd_card_t *)priv->card;
        dev_link_t *link = &card->link;
        conf_reg_t reg;
-       u_long default_cor; 
+       u_int default_cor; 
 
        TRACE_ENTER(priv->ndev.name);
 
@@ -713,6 +714,9 @@ dldwd_cs_event(event_t event, int priority,
 
        switch (event) {
        case CS_EVENT_CARD_REMOVAL:
+               /* FIXME: Erg.. this whole hw_ready thing looks racy
+                  to me.  this may not be fixable without changin the
+                  PCMCIA subsystem, though */
                priv->hw_ready = 0;
                dldwd_shutdown(priv);
                link->state &= ~DEV_PRESENT;
@@ -780,8 +784,7 @@ init_dldwd_cs(void)
 
        TRACE_ENTER("dldwd");
 
-       printk(KERN_DEBUG "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"
-              KERN_DEBUG "%s\n", version);
+       printk(KERN_DEBUG "%s\n", version);
 
        CardServices(GetCardServicesInfo, &serv);
        if (serv.Revision != CS_RELEASE_CODE) {
index f8fcbe5b5a038fe35a6c8874d73a44e0b41064f8..09f1d435b7574efabee3cc44d46d430019e8e5b6 100644 (file)
@@ -396,8 +396,9 @@ pci_disable_device(struct pci_dev *dev)
 
 /**
  * pci_enable_wake - enable device to generate PME# when suspended
- * @dev - PCI device to operate on
- * @enable - Flag to enable or disable generation
+ * @dev: - PCI device to operate on
+ * @state: - Current state of device.
+ * @enable: - Flag to enable or disable generation
  * 
  * Set the bits in the device's PM Capabilities to generate PME# when
  * the system is suspended. 
index d42545d625a58cc3e5509ca9ad52f72976ade8e9..6838566cde262a87fb134ff445ced8d0b7270a9d 100644 (file)
@@ -158,6 +158,15 @@ static void __init quirk_viaetbf(struct pci_dev *dev)
                pci_pci_problems|=PCIPCI_VIAETBF;
        }
 }
+static void __init quirk_vsfx(struct pci_dev *dev)
+{
+       if((pci_pci_problems&PCIPCI_VSFX)==0)
+       {
+               printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+               pci_pci_problems|=PCIPCI_VSFX;
+       }
+}
+
 
 /*
  *     Natoma has some interesting boundary conditions with Zoran stuff
@@ -434,6 +443,7 @@ static struct pci_fixup pci_fixups[] __initdata = {
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency },
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8371_1,       quirk_vialatency },
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      0x3112  /* Not out yet ? */,    quirk_vialatency },
+       { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C576,       quirk_vsfx },
        { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C597_0,     quirk_viaetbf },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C597_0,     quirk_vt82c598_id },
        { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C586_3,     quirk_vt82c586_acpi },
index cd25d8781be38b0adb20bec831e2745e57b757ba..fe39d9878e556b548eb71a862d8f454c48a05676 100644 (file)
@@ -934,7 +934,7 @@ static void pcic_bh(void *dummy)
                "we have a card coming in" electronics have seen it. 
                */
                if (events & SS_DETECT) 
-                       mdelay(2);
+                       mdelay(4);
                if (socket[i].handler)
                        socket[i].handler(socket[i].info, events);
        }
index 3f8ac6e235f55a159eb942803dc9b0319185d94f..70f086edc4d7f30c029bc217cb73d29cc8fcdcf6 100644 (file)
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
-#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
 #else
-#define AIC7XXX_CMDS_PER_DEVICE 8
+#define AIC7XXX_CMDS_PER_DEVICE 32
 #endif
 
 /*
  * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
  * NOTE: This does affect performance since it has to maintain statistics.
  */
-#ifdef CONFIG_AIC7XXX_PROC_STATS
+#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS
 #define AIC7XXX_PROC_STATS
 #endif
 
@@ -347,7 +347,7 @@ typedef struct
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
-#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
 #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
                               0, 0, 0, 0, 0, 0, 0, 0}
 #else
@@ -8865,6 +8865,7 @@ aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
     memset(p, 0, sizeof(struct aic7xxx_host));
     *p = *temp;
     p->host = host;
+    host->max_sectors = 512;
 
     p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
     if (p->scb_data != NULL)
index 7320eb6b6fa2cce3b81eff6cbe7922800db7e06e..14dcd389dad13525a6ab784b2592fab65ca4c203 100644 (file)
@@ -162,7 +162,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
   size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
 #else
   size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
index a1afb8e1cb738cf4d38da4a358d9e06d249d0994..a8d363eb9fd79e2452e50e1ce7454c33b29cbb2d 100644 (file)
 #include <asm/hydra.h>
 #include <asm/processor.h>
 #include <asm/feature.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
 
 #include "scsi.h"
 #include "hosts.h"
@@ -151,6 +155,7 @@ struct mesh_state {
        struct mesh_target tgts[8];
        void    *dma_cmd_space;
        struct device_node *ofnode;
+       u8*     mio_base;
 #ifndef MESH_NEW_STYLE_EH
        Scsi_Cmnd *completed_q;
        Scsi_Cmnd *completed_qtail;
@@ -210,6 +215,15 @@ static void set_dma_cmds(struct mesh_state *, Scsi_Cmnd *);
 static void halt_dma(struct mesh_state *);
 static int data_goes_out(Scsi_Cmnd *);
 static void do_abort(struct mesh_state *ms);
+static void set_mesh_power(struct mesh_state *ms, int state);
+
+#ifdef CONFIG_PMAC_PBOOK
+static int mesh_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier mesh_sleep_notifier = {
+       mesh_notify_sleep,
+       SLEEP_LEVEL_BLOCK,
+};
+#endif
 
 static struct notifier_block mesh_notifier = {
        mesh_notify_reboot,
@@ -244,6 +258,8 @@ mesh_detect(Scsi_Host_Template *tp)
        if (mesh == 0)
                mesh = find_compatible_devices("scsi", "chrp,mesh0");
        for (; mesh != 0; mesh = mesh->next) {
+               struct device_node *mio;
+               
                if (mesh->n_addrs != 2 || mesh->n_intrs != 2) {
                        printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
                               " (got %d,%d)", mesh->n_addrs, mesh->n_intrs);
@@ -309,8 +325,13 @@ mesh_detect(Scsi_Host_Template *tp)
                if (mesh_sync_period < minper)
                        mesh_sync_period = minper;
 
-               feature_set(mesh, FEATURE_MESH_enable);
-               mdelay(200);
+               ms->mio_base = 0;
+               for (mio = ms->ofnode->parent; mio; mio = mio->parent)
+                       if (strcmp(mio->name, "mac-io") == 0 && mio->n_addrs > 0)
+                               break;
+               if (mio)
+                       ms->mio_base = (u8 *) ioremap(mio->addrs[0].address, 0x40);
+               set_mesh_power(ms, 1);
 
                mesh_init(ms);
 
@@ -321,8 +342,12 @@ mesh_detect(Scsi_Host_Template *tp)
                ++nmeshes;
        }
 
-       if ((_machine == _MACH_Pmac) && (nmeshes > 0))
+       if ((_machine == _MACH_Pmac) && (nmeshes > 0)) {
+#ifdef CONFIG_PMAC_PBOOK
+               pmu_register_sleep_notifier(&mesh_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
                register_reboot_notifier(&mesh_notifier);
+       }
 
        return nmeshes;
 }
@@ -338,12 +363,70 @@ mesh_release(struct Scsi_Host *host)
                iounmap((void *) ms->mesh);
        if (ms->dma)
                iounmap((void *) ms->dma);
+       if (ms->mio_base)
+               iounmap((void *) ms->mio_base);
        kfree(ms->dma_cmd_space);
        free_irq(ms->meshintr, ms);
        feature_clear(ms->ofnode, FEATURE_MESH_enable);
        return 0;
 }
 
+static void
+set_mesh_power(struct mesh_state *ms, int state)
+{
+       if (_machine != _MACH_Pmac)
+               return;
+       if (state) {
+               feature_set(ms->ofnode, FEATURE_MESH_enable);
+               /* This seems to enable the termination power. strangely
+                  this doesn't fully agree with OF, but with MacOS */
+               if (ms->mio_base)
+                       out_8(ms->mio_base + 0x36, 0x70);
+               mdelay(200);
+       } else {
+               feature_clear(ms->ofnode, FEATURE_MESH_enable);
+               if (ms->mio_base)
+                       out_8(ms->mio_base + 0x36, 0x34);
+               mdelay(10);
+       }
+}                      
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int
+mesh_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+       struct mesh_state *ms;
+       
+       switch (when) {
+       case PBOOK_SLEEP_REQUEST:
+               /* XXX We should wait for current transactions and queue
+                * new ones that would be posted beyond this point 
+                */ 
+               break;
+       case PBOOK_SLEEP_REJECT:
+               break;
+               
+       case PBOOK_SLEEP_NOW:
+               for (ms = all_meshes; ms != 0; ms = ms->next) {
+                       disable_irq(ms->meshintr);
+                       set_mesh_power(ms, 0);
+               }
+               break;
+       case PBOOK_WAKE:
+               for (ms = all_meshes; ms != 0; ms = ms->next) {
+                       set_mesh_power(ms, 1);
+                       mesh_init(ms);
+                       enable_irq(ms->meshintr);
+               }
+               break;
+       }
+       return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
 int
 mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
index f52500046f3f4ea52d25a77fb8f65d8cb490fcb8..f6d4a49d034118874ff0ac629443ba63ee076442 100644 (file)
@@ -1,7 +1,7 @@
 /*
     btaudio - bt878 audio dma driver for linux 2.4.x
 
-    (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 2000 Gerd Knorr <kraxel@bytesex.org>
 
     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
@@ -32,9 +32,7 @@
 #include <linux/poll.h>
 #include <linux/sound.h>
 #include <linux/soundcard.h>
-#include <linux/slab.h>
 #include <asm/uaccess.h>
-#include <asm/io.h>
 
 
 /* mmio access */
@@ -91,7 +89,6 @@
 #define RISC_SYNC_VRO     0x0c
 
 #define HWBASE_AD (448000)
-#define HWBASE_DA 31928 /* 48000 */
 
 /* -------------------------------------------------------------- */
 
@@ -100,7 +97,8 @@ struct btaudio {
        struct btaudio *next;
 
        /* device info */
-       int            dsp_dev;
+       int            dsp_digital;
+       int            dsp_analog;
        int            mixer_dev;
        struct pci_dev *pci;
        unsigned int   irq;
@@ -142,14 +140,18 @@ struct btaudio {
        int mixcount;
        int sampleshift;
        int channels;
+       int analog;
 };
 
 static struct btaudio *btaudios = NULL;
-static unsigned int dsp = -1;
+static unsigned int dsp1 = -1;
+static unsigned int dsp2 = -1;
 static unsigned int mixer = -1;
 static unsigned int debug = 0;
 static unsigned int irq_debug = 0;
-static int analog = 0;
+static int digital = 1;
+static int analog = 1;
+static int rate = 32000;
 
 /* -------------------------------------------------------------- */
 
@@ -210,7 +212,8 @@ static int make_risc(struct btaudio *bta)
        if (bta->line_count > 255)
                return -EINVAL;
        if (debug)
-               printk("btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",
+               printk(KERN_DEBUG
+                      "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",
                       bta->buf_size,bta->block_bytes,bta->block_count,
                       bta->line_bytes,bta->line_count);
         rp = 0; bp = 0;
@@ -250,7 +253,7 @@ static int start_recording(struct btaudio *bta)
        btwrite((bta->line_count << 16) | bta->line_bytes,
                REG_PACKET_LEN);
        btwrite(IRQ_BTAUDIO, REG_INT_MASK);
-       if (analog) {
+       if (bta->analog) {
                btwrite(DMA_CTL_ACAP_EN |
                        DMA_CTL_RISC_EN |
                        DMA_CTL_FIFO_EN |
@@ -278,7 +281,7 @@ static int start_recording(struct btaudio *bta)
        bta->read_count = 0;
        bta->recording = 1;
        if (debug)
-               printk("btaudio: recording started\n");
+               printk(KERN_DEBUG "btaudio: recording started\n");
        return 0;
 }
 
@@ -287,15 +290,9 @@ static void stop_recording(struct btaudio *bta)
         btand(~15, REG_GPIO_DMA_CTL);
        bta->recording = 0;
        if (debug)
-               printk("btaudio: recording stopped\n");
+               printk(KERN_DEBUG "btaudio: recording stopped\n");
 }
 
-/* -------------------------------------------------------------- */
-
-static loff_t btaudio_llseek(struct file *file, loff_t offset, int origin)
-{
-        return -ESPIPE;
-}
 
 /* -------------------------------------------------------------- */
 
@@ -310,6 +307,8 @@ static int btaudio_mixer_open(struct inode *inode, struct file *file)
        if (NULL == bta)
                return -ENODEV;
 
+       if (debug)
+               printk("btaudio: open mixer [%d]\n",minor);
        file->private_data = bta;
        return 0;
 }
@@ -327,8 +326,9 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
 
        if (cmd == SOUND_MIXER_INFO) {
                mixer_info info;
-                strncpy(info.id, "bt878", sizeof(info.id));
-                strncpy(info.name, "Brooktree Bt878 audio", sizeof(info.name));
+               memset(&info,0,sizeof(info));
+                strncpy(info.id,"bt878",sizeof(info.id)-1);
+                strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1);
                 info.modify_counter = bta->mixcount;
                 if (copy_to_user((void *)arg, &info, sizeof(info)))
                         return -EFAULT;
@@ -336,8 +336,9 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
        }
        if (cmd == SOUND_OLD_MIXER_INFO) {
                _old_mixer_info info;
-                strncpy(info.id, "bt878", sizeof(info.id));
-                strncpy(info.name, "Brooktree Bt878 audio", sizeof(info.name));
+               memset(&info,0,sizeof(info));
+                strncpy(info.id,"bt878",sizeof(info.id)-1);
+                strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1);
                 if (copy_to_user((void *)arg, &info, sizeof(info)))
                         return -EFAULT;
                return 0;
@@ -423,7 +424,7 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
 
 static struct file_operations btaudio_mixer_fops = {
        owner:   THIS_MODULE,
-       llseek:  btaudio_llseek,
+       llseek:  no_llseek,
        open:    btaudio_mixer_open,
        release: btaudio_mixer_release,
        ioctl:   btaudio_mixer_ioctl,
@@ -431,23 +432,16 @@ static struct file_operations btaudio_mixer_fops = {
 
 /* -------------------------------------------------------------- */
 
-static int btaudio_dsp_open(struct inode *inode, struct file *file)
+static int btaudio_dsp_open(struct inode *inode, struct file *file,
+                           struct btaudio *bta, int analog)
 {
-       int minor = MINOR(inode->i_rdev);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->dsp_dev == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-
        down(&bta->lock);
        if (bta->users)
                goto busy;
        bta->users++;
        file->private_data = bta;
 
+       bta->analog = analog;
        bta->dma_block = 0;
        bta->read_offset = 0;
        bta->read_count = 0;
@@ -461,6 +455,38 @@ static int btaudio_dsp_open(struct inode *inode, struct file *file)
        return -EBUSY;
 }
 
+static int btaudio_dsp_open_digital(struct inode *inode, struct file *file)
+{
+       int minor = MINOR(inode->i_rdev);
+       struct btaudio *bta;
+
+       for (bta = btaudios; bta != NULL; bta = bta->next)
+               if (bta->dsp_digital == minor)
+                       break;
+       if (NULL == bta)
+               return -ENODEV;
+       
+       if (debug)
+               printk("btaudio: open digital dsp [%d]\n",minor);
+       return btaudio_dsp_open(inode,file,bta,0);
+}
+
+static int btaudio_dsp_open_analog(struct inode *inode, struct file *file)
+{
+       int minor = MINOR(inode->i_rdev);
+       struct btaudio *bta;
+
+       for (bta = btaudios; bta != NULL; bta = bta->next)
+               if (bta->dsp_analog == minor)
+                       break;
+       if (NULL == bta)
+               return -ENODEV;
+
+       if (debug)
+               printk("btaudio: open analog dsp [%d]\n",minor);
+       return btaudio_dsp_open(inode,file,bta,1);
+}
+
 static int btaudio_dsp_release(struct inode *inode, struct file *file)
 {
        struct btaudio *bta = file->private_data;
@@ -511,9 +537,9 @@ static ssize_t btaudio_dsp_read(struct file *file, char *buffer,
                if (nsrc > bta->buf_size - bta->read_offset)
                        nsrc = bta->buf_size - bta->read_offset;
                ndst = nsrc >> bta->sampleshift;
-
-               if ((analog  && 0 == bta->sampleshift) ||
-                   (!analog && 2 == bta->channels)) {
+               
+               if ((bta->analog  && 0 == bta->sampleshift) ||
+                   (!bta->analog && 2 == bta->channels)) {
                        /* just copy */
                        if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) {
                                if (0 == ret)
@@ -521,11 +547,11 @@ static ssize_t btaudio_dsp_read(struct file *file, char *buffer,
                                break;
                        }
 
-               } else if (!analog) {
+               } else if (!bta->analog) {
                        /* stereo => mono (digital audio) */
-                       __u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);
-                       __u16 *dst = (__u16*)(buffer + ret);
-                       __u16 avg;
+                       __s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset);
+                       __s16 *dst = (__s16*)(buffer + ret);
+                       __s16 avg;
                        int n = ndst>>1;
                        if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {
                                if (0 == ret)
@@ -533,9 +559,9 @@ static ssize_t btaudio_dsp_read(struct file *file, char *buffer,
                                break;
                        }
                        for (; n; n--, dst++) {
-                               avg  = *(src++) >> 1;
-                               avg += *(src++) >> 1;
-                               __put_user(avg,(__u16*)(dst));
+                               avg  = (__s16)le16_to_cpu(*src) / 2; src++;
+                               avg += (__s16)le16_to_cpu(*src) / 2; src++;
+                               __put_user(cpu_to_le16(avg),(__u16*)(dst));
                        }
 
                } else if (8 == bta->bits) {
@@ -600,7 +626,7 @@ static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
         case SNDCTL_DSP_SPEED:
                if (get_user(val, (int*)arg))
                        return -EFAULT;
-               if (analog) {
+               if (bta->analog) {
                        for (s = 0; s < 16; s++)
                                if (val << s >= HWBASE_AD*4/15)
                                        break;
@@ -610,7 +636,8 @@ static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
                        bta->sampleshift = s;
                        bta->decimation  = i;
                        if (debug)
-                               printk("btaudio: rate: req=%d  dec=%d shift=%d hwrate=%d swrate=%d\n",
+                               printk(KERN_DEBUG "btaudio: rate: req=%d  "
+                                      "dec=%d shift=%d hwrate=%d swrate=%d\n",
                                       val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s);
                } else {
                        bta->sampleshift = (bta->channels == 2) ? 0 : 1;
@@ -624,26 +651,30 @@ static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
                }
                /* fall through */
         case SOUND_PCM_READ_RATE:
-               if (analog) {
+               if (bta->analog) {
                        return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, (int*)arg);
                } else {
-                       return put_user(HWBASE_DA, (int*)arg);
+                       return put_user(rate, (int*)arg);
                }
 
         case SNDCTL_DSP_STEREO:
-               if (!analog) {
+               if (!bta->analog) {
                        if (get_user(val, (int*)arg))
                                return -EFAULT;
                        bta->channels    = (val > 0) ? 2 : 1;
                        bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       printk("btaudio: stereo=%d channels=%d\n",
-                              val,bta->channels);
+                       if (debug)
+                               printk(KERN_INFO
+                                      "btaudio: stereo=%d channels=%d\n",
+                                      val,bta->channels);
                } else {
                        if (val == 1)
                                return -EFAULT;
                        else {
                                bta->channels = 1;
-                               printk("btaudio: stereo=0 channels=1\n");
+                               if (debug)
+                                       printk(KERN_INFO
+                                              "btaudio: stereo=0 channels=1\n");
                        }
                }
                return put_user((bta->channels)-1, (int *)arg);
@@ -654,8 +685,10 @@ static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
                                return -EFAULT;
                        bta->channels    = (val > 1) ? 2 : 1;
                        bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       printk("btaudio: val=%d channels=%d\n",
-                              val,bta->channels);
+                       if (debug)
+                               printk(KERN_DEBUG
+                                      "btaudio: val=%d channels=%d\n",
+                                      val,bta->channels);
                }
                /* fall through */
         case SOUND_PCM_READ_CHANNELS:
@@ -683,7 +716,7 @@ static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
                        }
                }
                if (debug)
-                       printk("btaudio: fmt: bits=%d\n",bta->bits);
+                       printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits);
                 return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8,
                                (int*)arg);
                break;
@@ -736,10 +769,21 @@ static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct
        return mask;
 }
 
-static struct file_operations btaudio_dsp_fops = {
+static struct file_operations btaudio_digital_dsp_fops = {
        owner:   THIS_MODULE,
-       llseek:  btaudio_llseek,
-       open:    btaudio_dsp_open,
+       llseek:  no_llseek,
+       open:    btaudio_dsp_open_digital,
+       release: btaudio_dsp_release,
+       read:    btaudio_dsp_read,
+       write:   btaudio_dsp_write,
+       ioctl:   btaudio_dsp_ioctl,
+       poll:    btaudio_dsp_poll,
+};
+
+static struct file_operations btaudio_analog_dsp_fops = {
+       owner:   THIS_MODULE,
+       llseek:  no_llseek,
+       open:    btaudio_dsp_open_analog,
        release: btaudio_dsp_release,
        read:    btaudio_dsp_read,
        write:   btaudio_dsp_write,
@@ -769,7 +813,7 @@ static void btaudio_irq(int irq, void *dev_id, struct pt_regs * regs)
 
                if (irq_debug) {
                        int i;
-                       printk("btaudio: irq loop=%d risc=%x, bits:",
+                       printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:",
                               count, stat>>28);
                        for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
                                if (stat & (1 << i))
@@ -787,7 +831,7 @@ static void btaudio_irq(int irq, void *dev_id, struct pt_regs * regs)
                        bta->dma_block = stat >> 28;
                        if (bta->read_count + 2*bta->block_bytes > bta->buf_size) {
                                stop_recording(bta);
-                               printk("btaudio: buffer overrun\n");
+                               printk(KERN_INFO "btaudio: buffer overrun\n");
                        }
                        if (blocks > 0) {
                                bta->read_count += blocks * bta->block_bytes;
@@ -795,7 +839,8 @@ static void btaudio_irq(int irq, void *dev_id, struct pt_regs * regs)
                        }
                }
                if (count > 10) {
-                       printk("btaudio: Oops - irq mask cleared\n");
+                       printk(KERN_WARNING
+                              "btaudio: Oops - irq mask cleared\n");
                        btwrite(0, REG_INT_MASK);
                }
        }
@@ -831,7 +876,7 @@ static int __devinit btaudio_probe(struct pci_dev *pci_dev,
        bta->source     = 1;
        bta->bits       = 8;
        bta->channels   = 1;
-       if (analog) {
+       if (bta->analog) {
                bta->decimation  = 15;
        } else {
                bta->decimation  = 0;
@@ -843,7 +888,7 @@ static int __devinit btaudio_probe(struct pci_dev *pci_dev,
 
         pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
         pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &latency);
-        printk("btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
+        printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
               pci_dev->device,revision,pci_dev->bus->number,
               PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
         printk("irq: %d, latency: %d, memory: 0x%lx\n",
@@ -852,31 +897,44 @@ static int __devinit btaudio_probe(struct pci_dev *pci_dev,
        /* init hw */
         btwrite(0, REG_GPIO_DMA_CTL);
         btwrite(0, REG_INT_MASK);
-        btwrite(~(u32)0x0, REG_INT_STAT);
+        btwrite(~0x0UL, REG_INT_STAT);
        pci_set_master(pci_dev);
 
        if ((rc = request_irq(bta->irq, btaudio_irq, SA_SHIRQ|SA_INTERRUPT,
                               "btaudio",(void *)bta)) < 0) {
-               printk("btaudio: can't request irq (rc=%d)\n",rc);
+               printk(KERN_WARNING
+                      "btaudio: can't request irq (rc=%d)\n",rc);
                goto fail1;
        }
 
        /* register devices */
-       rc = bta->dsp_dev = register_sound_dsp(&btaudio_dsp_fops,dsp);
-       if (rc < 0) {
-               printk("btaudio: can't register dsp (rc=%d)\n",rc);
-               goto fail2;
+       if (digital) {
+               rc = bta->dsp_digital =
+                       register_sound_dsp(&btaudio_digital_dsp_fops,dsp1);
+               if (rc < 0) {
+                       printk(KERN_WARNING
+                              "btaudio: can't register digital dsp (rc=%d)\n",rc);
+                       goto fail2;
+               }
        }
        if (analog) {
-               rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);
+               rc = bta->dsp_analog =
+                       register_sound_dsp(&btaudio_analog_dsp_fops,dsp2);
                if (rc < 0) {
-                       printk("btaudio: can't register mixer (rc=%d)\n",rc);
+                       printk(KERN_WARNING
+                              "btaudio: can't register analog dsp (rc=%d)\n",rc);
                        goto fail3;
                }
+               rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);
+               if (rc < 0) {
+                       printk(KERN_WARNING
+                              "btaudio: can't register mixer (rc=%d)\n",rc);
+                       goto fail4;
+               }
        }
        if (debug)
-               printk("btaudio: dsp: minor=%d, mixer: minor=%d\n",
-                      bta->dsp_dev,bta->mixer_dev);
+               printk(KERN_DEBUG "btaudio: minors: digital=%d, analog=%d, mixer=%d\n",
+                      bta->dsp_digital, bta->dsp_analog, bta->mixer_dev);
 
        /* hook into linked list */
        bta->next = btaudios;
@@ -885,8 +943,11 @@ static int __devinit btaudio_probe(struct pci_dev *pci_dev,
        pci_set_drvdata(pci_dev,bta);
         return 0;
 
+ fail4:
+       unregister_sound_dsp(bta->dsp_analog);
  fail3:
-       unregister_sound_dsp(bta->dsp_dev);
+       if (digital)
+               unregister_sound_dsp(bta->dsp_digital);
  fail2:
         free_irq(bta->irq,bta);        
  fail1:
@@ -904,12 +965,16 @@ static void __devexit btaudio_remove(struct pci_dev *pci_dev)
        /* turn off all DMA / IRQs */
         btand(~15, REG_GPIO_DMA_CTL);
         btwrite(0, REG_INT_MASK);
-        btwrite(~(u32)0x0, REG_INT_STAT);
+        btwrite(~0x0UL, REG_INT_STAT);
 
        /* unregister devices */
-       unregister_sound_dsp(bta->dsp_dev);
-       if (analog)
+       if (digital) {
+               unregister_sound_dsp(bta->dsp_digital);
+       }
+       if (analog) {
+               unregister_sound_dsp(bta->dsp_analog);
                unregister_sound_mixer(bta->mixer_dev);
+       }
 
        /* free resources */
        free_buffer(bta);
@@ -950,8 +1015,10 @@ static struct pci_driver btaudio_pci_driver = {
 
 int btaudio_init_module(void)
 {
-       printk("btaudio: driver version 0.5 loaded [%s mode]\n",
-              analog ? "audio A/D" : "digital audio");
+       printk(KERN_INFO "btaudio: driver version 0.6 loaded [%s%s%s]\n",
+              analog ? "analog" : "",
+              analog && digital ? "+" : "",
+              digital ? "digital" : "");
        return pci_module_init(&btaudio_pci_driver);
 }
 
@@ -964,15 +1031,19 @@ void btaudio_cleanup_module(void)
 module_init(btaudio_init_module);
 module_exit(btaudio_cleanup_module);
 
-MODULE_PARM(dsp,"i");
+MODULE_PARM(dsp1,"i");
+MODULE_PARM(dsp2,"i");
 MODULE_PARM(mixer,"i");
 MODULE_PARM(debug,"i");
 MODULE_PARM(irq_debug,"i");
+MODULE_PARM(digital,"i");
 MODULE_PARM(analog,"i");
+MODULE_PARM(rate,"i");
 
 MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
-MODULE_DESCRIPTION("btaudio - bt878 audio dma driver");
+MODULE_DESCRIPTION("bt878 audio dma driver");
 MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
 
 /*
  * Local variables:
index 4388f7f34c967e11d8e64644ccb99c734dae7ceb..869fa7d8b83fb6d825afbfb43319216c654026f6 100644 (file)
@@ -303,6 +303,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(0x002c), 
+               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),
@@ -313,6 +318,11 @@ static struct {
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
                0,0,0,0,
                0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086), 
+               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),
@@ -363,6 +373,11 @@ static struct {
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
                0,0,0,0,
                0,1,1,-1},
+       {"Sound Blaster AWE 32",
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047),
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,0,0,
+               0,1,1,-1},
        {"Sound Blaster AWE 32",
                ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
@@ -537,12 +552,18 @@ static struct isapnp_device_id id_table[] __devinitdata = {
        {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
 
+       {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c), 
+               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(0x0086), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
 
+       {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086), 
+               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 15853eedef3f995b1a684c616e7921bb681e3f6d..21d1eadce554114344f8421c7000c485467735f7 100644 (file)
@@ -457,11 +457,12 @@ static void ymf_wait_dac(struct ymf_state *state)
        }
 #endif
 
+       set_current_state(TASK_UNINTERRUPTIBLE);
        while (ypcm->running) {
                spin_unlock_irqrestore(&unit->reg_lock, flags);
-               set_current_state(TASK_UNINTERRUPTIBLE);
                schedule();
                spin_lock_irqsave(&unit->reg_lock, flags);
+               set_current_state(TASK_UNINTERRUPTIBLE);
        }
        spin_unlock_irqrestore(&unit->reg_lock, flags);
 
@@ -1198,12 +1199,13 @@ ymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
        ret = 0;
 
        add_wait_queue(&dmabuf->wait, &waita);
+       set_current_state(TASK_INTERRUPTIBLE);
        while (count > 0) {
                spin_lock_irqsave(&unit->reg_lock, flags);
                if (unit->suspended) {
                        spin_unlock_irqrestore(&unit->reg_lock, flags);
-                       set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
                        if (signal_pending(current)) {
                                if (!ret) ret = -EAGAIN;
                                break;
@@ -1241,9 +1243,9 @@ ymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
                           is TOO LATE for the process to be scheduled to run (scheduler latency)
                           which results in a (potential) buffer overrun. And worse, there is
                           NOTHING we can do to prevent it. */
-                       set_current_state(TASK_INTERRUPTIBLE);
                        tmo = schedule_timeout(tmo);
                        spin_lock_irqsave(&state->unit->reg_lock, flags);
+                       set_current_state(TASK_INTERRUPTIBLE);
                        if (tmo == 0 && dmabuf->count == 0) {
                                printk(KERN_ERR "ymfpci%d: recording schedule timeout, "
                                    "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
@@ -1326,12 +1328,13 @@ ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
        redzone *= 3;   /* 2 redzone + 1 possible uncertainty reserve. */
 
        add_wait_queue(&dmabuf->wait, &waita);
+       set_current_state(TASK_INTERRUPTIBLE);
        while (count > 0) {
                spin_lock_irqsave(&unit->reg_lock, flags);
                if (unit->suspended) {
                        spin_unlock_irqrestore(&unit->reg_lock, flags);
-                       set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
                        if (signal_pending(current)) {
                                if (!ret) ret = -EAGAIN;
                                break;
@@ -1389,8 +1392,8 @@ ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                                if (!ret) ret = -EAGAIN;
                                break;
                        }
-                       set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
                        if (signal_pending(current)) {
                                if (!ret) ret = -ERESTARTSYS;
                                break;
index 0b8d2bc170f2b8ecf457c17b06ae53b981d313ac..f46987e78c266f839c81b18e826f644f888d2d11 100644 (file)
@@ -1271,6 +1271,7 @@ module_exit( CDCEther_exit );
 
 MODULE_AUTHOR("Brad Hards and another");
 MODULE_DESCRIPTION("USB CDC Ethernet driver");
+MODULE_LICENSE("GPL");
 
 MODULE_DEVICE_TABLE (usb, CDCEther_ids);
 
index 194fd0fca361ec96f97457d1614e2757fbde65b2..0fff71177e863d5ce37b719e7acc5b7989802dbd 100644 (file)
  *    - Added Epson Perfection 1640SU and 1640SU Photo.  Thanks to
  *      Jean-Luc <f5ibh@db0bm.ampr.org>.
  *
+ * 0.4.6 08/16/2001 Yves Duret <yduret@mandrakesoft.com>
+ *    - added devfs support (from printer.c)
+ *
  *  TODO
  *
  *    - Performance
@@ -579,6 +582,100 @@ read_scanner(struct file * file, char * buffer,
        return ret ? ret : bytes_read;
 }
 
+#ifdef SCN_IOCTL
+static int
+ioctl_scanner(struct inode *inode, struct file *file,
+             unsigned int cmd, unsigned long arg)
+{
+       struct usb_device *dev;
+
+       int result;
+
+       kdev_t scn_minor;
+
+       scn_minor = USB_SCN_MINOR(inode);
+
+       if (!p_scn_table[scn_minor]) {
+               err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
+               return -ENODEV;
+       }
+
+       dev = p_scn_table[scn_minor]->scn_dev;
+
+       switch (cmd)
+       {
+       case IOCTL_SCANNER_VENDOR :
+               return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+       case IOCTL_SCANNER_PRODUCT :
+               return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
+       case PV8630_IOCTL_INREQUEST :
+       {
+               struct {
+                       __u8  data;
+                       __u8  request;
+                       __u16 value;
+                       __u16 index;
+               } args;
+
+               if (copy_from_user(&args, (void *)arg, sizeof(args)))
+                       return -EFAULT;
+
+               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                        args.request, USB_TYPE_VENDOR|
+                                        USB_RECIP_DEVICE|USB_DIR_IN,
+                                        args.value, args.index, &args.data,
+                                        1, HZ*5);
+
+               dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
+
+               if (copy_to_user((void *)arg, &args, sizeof(args)))
+                       return -EFAULT;
+
+               dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
+
+               return result;
+       }
+       case PV8630_IOCTL_OUTREQUEST :
+       {
+               struct {
+                       __u8  request;
+                       __u16 value;
+                       __u16 index;
+               } args;
+
+               if (copy_from_user(&args, (void *)arg, sizeof(args)))
+                       return -EFAULT;
+
+               dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
+
+               result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                        args.request, USB_TYPE_VENDOR|
+                                        USB_RECIP_DEVICE|USB_DIR_OUT,
+                                        args.value, args.index, NULL,
+                                        0, HZ*5);
+
+               dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
+
+               return result;
+       }
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+#endif /* SCN_IOCTL */
+
+static struct
+file_operations usb_scanner_fops = {
+       read:           read_scanner,
+       write:          write_scanner,
+#ifdef SCN_IOCTL
+       ioctl:          ioctl_scanner,
+#endif /* SCN_IOCTL */
+       open:           open_scanner,
+       release:        close_scanner,
+};
+
 static void *
 probe_scanner(struct usb_device *dev, unsigned int ifnum,
              const struct usb_device_id *id)
@@ -813,6 +910,14 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
 
        init_MUTEX(&(scn->gen_lock));
 
+       /* if we have devfs, create with perms=660 */
+       scn->devfs = devfs_register(usb_devfs_handle, "scanner",
+                                     DEVFS_FL_DEFAULT, USB_MAJOR,
+                                     SCN_BASE_MNR + scn_minor,
+                                     S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+                                     S_IWGRP, &usb_scanner_fops, NULL);
+
+
        return p_scn_table[scn_minor] = scn;
 }
 
@@ -828,6 +933,8 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
         usb_driver_release_interface(&scanner_driver,
                 &scn->scn_dev->actconfig->interface[scn->ifnum]);
 
+       devfs_unregister (scn->devfs);
+
        kfree(scn->ibuf);
        kfree(scn->obuf);
 
@@ -836,99 +943,6 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
        kfree (scn);
 }
 
-#ifdef SCN_IOCTL
-static int
-ioctl_scanner(struct inode *inode, struct file *file,
-             unsigned int cmd, unsigned long arg)
-{
-       struct usb_device *dev;
-
-       int result;
-
-       kdev_t scn_minor;
-
-       scn_minor = USB_SCN_MINOR(inode);
-
-       if (!p_scn_table[scn_minor]) {
-               err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
-               return -ENODEV;
-       }
-
-       dev = p_scn_table[scn_minor]->scn_dev;
-
-       switch (cmd)
-       {
-       case IOCTL_SCANNER_VENDOR :
-               return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
-       case IOCTL_SCANNER_PRODUCT :
-               return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
-       case PV8630_IOCTL_INREQUEST :
-       {
-               struct {
-                       __u8  data;
-                       __u8  request;
-                       __u16 value;
-                       __u16 index;
-               } args;
-
-               if (copy_from_user(&args, (void *)arg, sizeof(args)))
-                       return -EFAULT;
-
-               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                                        args.request, USB_TYPE_VENDOR|
-                                        USB_RECIP_DEVICE|USB_DIR_IN,
-                                        args.value, args.index, &args.data,
-                                        1, HZ*5);
-
-               dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
-
-               if (copy_to_user((void *)arg, &args, sizeof(args)))
-                       return -EFAULT;
-
-               dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
-
-               return result;
-       }
-       case PV8630_IOCTL_OUTREQUEST :
-       {
-               struct {
-                       __u8  request;
-                       __u16 value;
-                       __u16 index;
-               } args;
-
-               if (copy_from_user(&args, (void *)arg, sizeof(args)))
-                       return -EFAULT;
-
-               dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
-
-               result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                        args.request, USB_TYPE_VENDOR|
-                                        USB_RECIP_DEVICE|USB_DIR_OUT,
-                                        args.value, args.index, NULL,
-                                        0, HZ*5);
-
-               dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
-
-               return result;
-       }
-       default:
-               return -ENOTTY;
-       }
-       return 0;
-}
-#endif /* SCN_IOCTL */
-
-static struct
-file_operations usb_scanner_fops = {
-       read:           read_scanner,
-       write:          write_scanner,
-#ifdef SCN_IOCTL
-       ioctl:          ioctl_scanner,
-#endif /* SCN_IOCTL */
-       open:           open_scanner,
-       release:        close_scanner,
-};
 
 static struct
 usb_driver scanner_driver = {
index d1e1908ea6856c2ad7a47cc8108f3e033585c4f1..e4b21bad0368ada425b1b70a885244ca2952bba5 100644 (file)
@@ -5,6 +5,8 @@
  *
  * David E. Nelson (dnelson@jump.net)
  *
+ * 08/16/2001 added devfs support Yves Duret <yduret@mandrakesoft.com>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
@@ -31,6 +33,7 @@
 #include <linux/ioctl.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
 
 // #define DEBUG
 
@@ -40,6 +43,7 @@ static __s32 vendor=-1, product=-1, read_timeout=0;
 
 MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
 MODULE_DESCRIPTION("USB Scanner Driver");
+MODULE_LICENSE("GPL");
 
 MODULE_PARM(vendor, "i");
 MODULE_PARM_DESC(vendor, "User specified USB idVendor");
@@ -174,6 +178,7 @@ MODULE_DEVICE_TABLE (usb, scanner_device_ids);
 
 struct scn_usb_data {
        struct usb_device *scn_dev;
+       devfs_handle_t devfs;   /* devfs device */
        struct urb scn_irq;
        unsigned int ifnum;     /* Interface number of the USB device */
        kdev_t scn_minor;       /* Scanner minor - used in disconnect() */
@@ -190,3 +195,5 @@ struct scn_usb_data {
 static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
 
 static struct usb_driver scanner_driver;
+
+extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
index 6a1a4eeb0439f65af497be71a6684107e5186c78..3d8a52aa675faaa07c34d105199087ce949e0e30 100644 (file)
@@ -346,6 +346,7 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
 
        /* show the GUID of the device */
        SPRINTF("         GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+       SPRINTF("     Attached: %d\n", us->pusb_dev != NULL);
 
        /*
         * Calculate start of next buffer, and return value.
index f5ccb10ea2ca7febe6663b7edf0a965504ee506a..6bb4b6c926e289ff7016b80ec809ebd6780d5c01 100644 (file)
@@ -3021,6 +3021,11 @@ uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
 
        if (pci_enable_device(dev) < 0)
                return -ENODEV;
+               
+       if (!dev->irq) {
+               err("found UHCI device with no IRQ assigned. check BIOS settings!");
+               return -ENODEV;
+       }
        
        pci_set_master(dev);
 
index 7c1eb7e5cddd46c3d560994932607ef34e3bb414..0ed344eff4b7afd3f36144c6adcdffa8caa11de2 100644 (file)
@@ -1,12 +1,13 @@
 /*
- * $Id: wacom.c,v 1.14 2000/11/23 09:34:32 vojtech Exp $
+ * $Id: wacom.c,v 1.22 2001/04/26 11:26:09 vojtech Exp $
  *
- *  Copyright (c) 2000 Vojtech Pavlik          <vojtech@suse.cz>
+ *  Copyright (c) 2000-2001 Vojtech Pavlik     <vojtech@suse.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen       <abach@stofanet.dk>
  *  Copyright (c) 2000 Clifford Wolf           <clifford@clifford.at>
  *  Copyright (c) 2000 Sam Mosel               <sam.mosel@computer.org>
  *  Copyright (c) 2000 James E. Blair          <corvus@gnu.org>
  *  Copyright (c) 2000 Daniel Egger            <egger@suse.de>
+ *  Copyright (c) 2001 Frederic Lepied         <flepied@mandrakesoft.com>
  *
  *  USB Wacom Graphire and Wacom Intuos tablet support
  *
  *     v1.12 (de) - Add support for two more inking pen IDs
  *     v1.14 (vp) - Use new USB device id probing scheme.
  *                  Fix Wacom Graphire mouse wheel
+ *     v1.18 (vp) - Fix mouse wheel direction
+ *                  Make mouse relative
+ *      v1.20 (fl) - Report tool id for Intuos devices
+ *                 - Multi tools support
+ *                 - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
+ *                 - Add PL models support
+ *                - Fix Wacom Graphire mouse wheel again
+ *     v1.21 (vp) - Removed protocol descriptions
+ *                - Added MISC_SERIAL for tool serial numbers
  *           (gb) - Identify version on module load.
  */
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.14"
+#define DRIVER_VERSION "v1.21"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
-
-/*
- * Wacom Graphire packet:
- *
- * byte 0: report ID (2)
- * byte 1: bit7                pointer in range
- *        bit5-6       pointer type 0 - pen, 1 - rubber, 2 - mouse
- *        bit4         1 ?
- *        bit3         0 ?
- *        bit2         mouse middle button / pen button2
- *        bit1         mouse right button / pen button1
- *        bit0         mouse left button / touch
- * byte 2: X low bits
- * byte 3: X high bits
- * byte 4: Y low bits
- * byte 5: Y high bits
- * byte 6: pen pressure low bits / mouse wheel
- * byte 7: pen presure high bits / mouse distance
- *
- * There are also two single-byte feature reports (2 and 3).
- *
- * Wacom Intuos status packet:
- *
- * byte 0: report ID (2)
- * byte 1: bit7                1 - sync bit
- *        bit6         pointer in range
- *        bit5         pointer type report
- *        bit4         0 ?
- *        bit3         mouse packet type
- *        bit2         pen button2
- *        bit1         pen button1
- *        bit0         0 ?
- * byte 2: X high bits
- * byte 3: X low bits
- * byte 4: Y high bits
- * byte 5: Y low bits
- *
- * Pen packet:
- *
- * byte 6: bits 0-7: pressure  (bits 2-9)
- * byte 7: bits 6-7: pressure  (bits 0-1)
- * byte 7: bits 0-5: X tilt    (bits 1-6)
- * byte 8: bit    7: X tilt    (bit  0)
- * byte 8: bits 0-6: Y tilt    (bits 0-6)
- * byte 9: bits 4-7: distance
- *
- * Mouse packet type 0:
- *
- * byte 6: bits 0-7: wheel     (bits 2-9)
- * byte 7: bits 6-7: wheel     (bits 0-1)
- * byte 7: bits 0-5: 0
- * byte 8: bits 6-7: 0
- * byte 8: bit    5: left extra button
- * byte 8: bit    4: right extra button
- * byte 8: bit    3: wheel      (sign)
- * byte 8: bit    2: right button
- * byte 8: bit    1: middle button
- * byte 8: bit    0: left button
- * byte 9: bits 4-7: distance
- *
- * Mouse packet type 1:
- *
- * byte 6: bits 0-7: rotation  (bits 2-9)
- * byte 7: bits 6-7: rotation  (bits 0-1)
- * byte 7: bit    5: rotation  (sign)
- * byte 7: bits 0-4: 0
- * byte 8: bits 0-7: 0
- * byte 9: bits 4-7: distance
- */
+MODULE_LICENSE("GPL");
 
 #define USB_VENDOR_ID_WACOM    0x056a
 
@@ -160,25 +102,56 @@ struct wacom {
        struct usb_device *usbdev;
        struct urb irq;
        struct wacom_features *features;
-       int tool;
+       int tool[2];
        int open;
+       int x, y;
+       __u32 serial[2];
 };
 
-static void wacom_graphire_irq(struct urb *urb)
+static void wacom_pl_irq(struct urb *urb)
 {
        struct wacom *wacom = urb->context;
        unsigned char *data = wacom->data;
        struct input_dev *dev = &wacom->dev;
+       int prox;
 
        if (urb->status) return;
 
        if (data[0] != 2)
                dbg("received unknown report #%d", data[0]);
 
-       if ( data[1] & 0x80 ) {
-               input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
-               input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8));
+       prox = data[1] & 0x20;
+       
+       input_report_key(dev, BTN_TOOL_PEN, prox);
+       
+       if (prox) {
+               int pressure = (data[4] & 0x04) >> 2 | ((__u32)(data[7] & 0x7f) << 1);
+
+               input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 8) | ((__u32)(data[1] & 0x03) << 16));
+               input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 8) | ((__u32)(data[4] & 0x03) << 8));
+               input_report_abs(dev, ABS_PRESSURE, (data[7] & 0x80) ? (255 - pressure) : (pressure + 255));
+               input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
+               input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
+               input_report_key(dev, BTN_STYLUS2, data[4] & 0x20);
        }
+       
+       input_event(dev, EV_MSC, MSC_SERIAL, 0);
+}
+
+static void wacom_graphire_irq(struct urb *urb)
+{
+       struct wacom *wacom = urb->context;
+       unsigned char *data = wacom->data;
+       struct input_dev *dev = &wacom->dev;
+       int x, y;
+
+       if (urb->status) return;
+
+       if (data[0] != 2)
+               dbg("received unknown report #%d", data[0]);
+
+       x = data[2] | ((__u32)data[3] << 8);
+       y = data[4] | ((__u32)data[5] << 8);
 
        switch ((data[1] >> 5) & 3) {
 
@@ -197,14 +170,25 @@ static void wacom_graphire_irq(struct urb *urb)
                        input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
                        input_report_abs(dev, ABS_DISTANCE, data[7]);
                        input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+
+                       input_report_abs(dev, ABS_X, x);
+                       input_report_abs(dev, ABS_Y, y);
+
+                       input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
                        return;
        }
 
-       input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+       if (data[1] & 0x80) {
+               input_report_abs(dev, ABS_X, wacom->x = x);
+               input_report_abs(dev, ABS_Y, wacom->y = y);
+       }
 
+       input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
        input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
        input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
        input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
+
+       input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
 }
 
 static void wacom_intuos_irq(struct urb *urb)
@@ -213,35 +197,47 @@ static void wacom_intuos_irq(struct urb *urb)
        unsigned char *data = wacom->data;
        struct input_dev *dev = &wacom->dev;
        unsigned int t;
+       int idx;
 
        if (urb->status) return;
 
        if (data[0] != 2)
                dbg("received unknown report #%d", data[0]);
 
-       if (((data[1] >> 5) & 0x3) == 0x2) {                            /* Enter report */
+       /* tool number */
+       idx = data[1] & 0x01;
+
+       if ((data[1] & 0xfc) == 0xc0) {                                         /* Enter report */
+
+               wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 4) +           /* serial number of the tool */
+                       ((__u32)data[4] << 16) + ((__u32)data[5] << 12) +
+                       ((__u32)data[6] << 4) + (data[7] >> 4);
 
                switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
                        case 0x832:
-                       case 0x812:
-                       case 0x012: wacom->tool = BTN_TOOL_PENCIL;      break;  /* Inking pen */
+                       case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL;         break;  /* Inking pen */
                        case 0x822:
-                       case 0x022: wacom->tool = BTN_TOOL_PEN;         break;  /* Pen */
-                       case 0x032: wacom->tool = BTN_TOOL_BRUSH;       break;  /* Stroke pen */
-                       case 0x094: wacom->tool = BTN_TOOL_MOUSE;       break;  /* Mouse 4D */
-                       case 0x096: wacom->tool = BTN_TOOL_LENS;        break;  /* Lens cursor */
+                       case 0x022: wacom->tool[idx] = BTN_TOOL_PEN;            break;  /* Pen */
+                       case 0x812:
+                       case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH;          break;  /* Stroke pen */
+                       case 0x09c:
+                       case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE;          break;  /* Mouse 4D */
+                       case 0x096: wacom->tool[idx] = BTN_TOOL_LENS;           break;  /* Lens cursor */
                        case 0x82a:
-                       case 0x0fa: wacom->tool = BTN_TOOL_RUBBER;      break;  /* Eraser */
-                       case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH;    break;  /* Airbrush */
-                       default:    wacom->tool = BTN_TOOL_PEN;         break;  /* Unknown tool */
+                       case 0x91a:
+                       case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER;         break;  /* Eraser */
+                       case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH;       break;  /* Airbrush */
+                       default:    wacom->tool[idx] = BTN_TOOL_PEN;            break;  /* Unknown tool */
                }       
-               input_report_key(dev, wacom->tool, 1);
+
+               input_report_key(dev, wacom->tool[idx], 1);
+               input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
                return;
        }
 
-       if ((data[1] | data[2] | data[3] | data[4] | data[5] |
-            data[6] | data[7] | data[8] | data[9]) == 0x80) {          /* Exit report */
-               input_report_key(dev, wacom->tool, 0);
+       if ((data[1] & 0xfe) == 0x80) {                                         /* Exit report */
+               input_report_key(dev, wacom->tool[idx], 0);
+               input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
                return;
        }
 
@@ -249,42 +245,52 @@ static void wacom_intuos_irq(struct urb *urb)
        input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
        input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
 
-       switch (wacom->tool) {
+       if ((data[1] & 0xb8) == 0xa0) {                                         /* general pen packet */
+               input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+               input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+               input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+               input_report_key(dev, BTN_STYLUS, data[1] & 2);
+               input_report_key(dev, BTN_STYLUS2, data[1] & 4);
+               input_report_key(dev, BTN_TOUCH, t > 10);
+       }
 
-               case BTN_TOOL_PENCIL:
-               case BTN_TOOL_PEN:
-               case BTN_TOOL_BRUSH:
-               case BTN_TOOL_RUBBER:
-               case BTN_TOOL_AIRBRUSH:
+       if ((data[1] & 0xbc) == 0xb4) {                                         /* airbrush second packet */
+               input_report_abs(dev, ABS_WHEEL, ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+               input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+               input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+       }
+       
+       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {             /* 4D mouse or Lens cursor packets */
 
-                       input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
-                       input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
-                       input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
-                       input_report_key(dev, BTN_STYLUS, data[1] & 2);
-                       input_report_key(dev, BTN_STYLUS2, data[1] & 4);
-                       input_report_key(dev, BTN_TOUCH, t > 10);
-                       break;
+               if (data[1] & 0x02) {                                           /* Rotation packet */
 
-               case BTN_TOOL_MOUSE:
-               case BTN_TOOL_LENS:
+                       input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
+                                        ((__u32)data[6] << 2) | ((data[7] >> 6) & 3):
+                                        (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 3))) - 1);
 
-                       if (data[1] & 0x02) {                   /* Rotation packet */
-                               input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
-                                       ((__u32)data[6] << 2) | ((data[7] >> 6) & 3):
-                                       (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 3))) - 1);
-                               break;
-                       }
+               } else {
 
                        input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
                        input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
                        input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
-                       input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
-                       input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
-                       input_report_abs(dev, ABS_THROTTLE,  (data[8] & 0x08) ?
-                               ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
-                               -((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
-                       break;
-         }
+
+                       if ((data[1] & 0x10) == 0) {                            /* 4D mouse packets */
+
+                               input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
+                               input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
+                               input_report_abs(dev, ABS_THROTTLE,  (data[8] & 0x08) ?
+                                                ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
+                                                -((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+
+                       } else {                                                /* Lens cursor packets */
+
+                               input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
+                               input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
+                       }
+               }
+       }
+       
+       input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 }
 
 #define WACOM_INTUOS_TOOLS     (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
@@ -304,6 +310,8 @@ struct wacom_features wacom_features[] = {
                0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
        { "Wacom Intuos 12x18", 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
                0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
+       { "Wacom PL500",        8,  12328, 9256,   511, 32, wacom_pl_irq,
+               0,  0, 0, 0 },
        { NULL , 0 }
 };
 
@@ -314,6 +322,7 @@ struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), driver_info: 3 },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), driver_info: 4 },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), driver_info: 5 },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), driver_info: 6 },
        { }
 };
 
@@ -351,12 +360,13 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
 
        wacom->features = wacom_features + id->driver_info;
 
-       wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit;
-       wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | wacom->features->absbit;
+       wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) | wacom->features->evbit;
+       wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | wacom->features->absbit;
        wacom->dev.relbit[0] |= wacom->features->relbit;
        wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | wacom->features->btnbit;
        wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) |
                BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit;
+       wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
 
        wacom->dev.absmax[ABS_X] = wacom->features->x_max;
        wacom->dev.absmax[ABS_Y] = wacom->features->y_max;
@@ -364,6 +374,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
        wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max;
        wacom->dev.absmax[ABS_TILT_X] = 127;
        wacom->dev.absmax[ABS_TILT_Y] = 127;
+       wacom->dev.absmax[ABS_WHEEL] = 1023;
 
        wacom->dev.absmin[ABS_RZ] = -900;
        wacom->dev.absmax[ABS_RZ] = 899;
index 3c5f654e91a506e23353632b1d08332d36c177c5..a69f35203dff57feffd19003518c45f1ab8d495e 100644 (file)
@@ -586,9 +586,11 @@ sizechange:
        fb->cursor.hwsize.fbx = 32;
        fb->cursor.hwsize.fby = 32;
        
-       if (depth > 1 && !fb->color_map)
+       if (depth > 1 && !fb->color_map) {
                fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
-               
+               return -ENOMEM;
+       }
+                       
        switch(fbtype) {
 #ifdef CONFIG_FB_CGSIX
        case FBTYPE_SUNFAST_COLOR:
@@ -687,3 +689,5 @@ int __init sun3fb_init(void)
        }
 #endif                 
 }
+
+MODULE_LICENSE("GPL");
index c0909b2424d1de6999d56af9a5ca22cd95300075..7bf62e0a60d7f694b256aaba0db62a42c2a29b1e 100644 (file)
@@ -1340,9 +1340,13 @@ void __bforget(struct buffer_head * buf)
        spin_unlock(&lru_list_lock);
 }
 
-/*
- * bread() reads a specified block and returns the buffer that contains
- * it. It returns NULL if the block was unreadable.
+/**
+ *     bread() - reads a specified block and returns the bh
+ *     @block: number of block
+ *     @size: size (in bytes) to read
+ * 
+ *     Reads a specified block, and returns buffer head that
+ *     contains it. It returns NULL if the block was unreadable.
  */
 struct buffer_head * bread(kdev_t dev, int block, int size)
 {
index e7ca71fa2b689a112bbf4388d101dc2447144858..d0c679e995d1a1550cb3400f4ec019e59ccfdaa9 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -598,7 +598,7 @@ flush_failed:
  */
 static inline int must_not_trace_exec(struct task_struct * p)
 {
-       return (p->ptrace & PT_PTRACED) && !cap_raised(p->p_pptr->cap_effective, CAP_SYS_PTRACE);
+       return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP);
 }
 
 /* 
index 86cc094d8208c90ff22911a76c34c76496d1538d..b0c1b44ce2a2fd52479af4437352350c02ef9164 100644 (file)
@@ -329,6 +329,10 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
        int err;
        if (current->link_count >= 8)
                goto loop;
+       if (current->need_resched) {
+               current->state = TASK_RUNNING;
+               schedule();
+       }
        current->link_count++;
        UPDATE_ATIME(dentry->d_inode);
        err = dentry->d_inode->i_op->follow_link(dentry, nd);
index 2d950382430f9a341034958fa0e17418d09923c7..59d6a4ece0659f0d2753a466dafb9ae7a4dbda30 100644 (file)
@@ -2,13 +2,14 @@
 #define __ASM_APIC_H
 
 #include <linux/config.h>
+#include <linux/pm.h>
 #include <asm/apicdef.h>
 #include <asm/system.h>
 
-#define APIC_DEBUG 1
-
 #ifdef CONFIG_X86_LOCAL_APIC
 
+#define APIC_DEBUG 0
+
 #if APIC_DEBUG
 #define Dprintk(x...) printk(x)
 #else
@@ -39,8 +40,6 @@ static __inline__ void apic_wait_icr_idle(void)
        do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
 }
 
-extern unsigned int apic_timer_irqs [NR_CPUS];
-
 #ifdef CONFIG_X86_GOOD_APIC
 # define FORCE_READ_AROUND_WRITE 0
 # define apic_read_around(x)
@@ -70,11 +69,28 @@ extern void disconnect_bsp_APIC (void);
 extern void disable_local_APIC (void);
 extern int verify_local_APIC (void);
 extern void cache_APIC_registers (void);
-extern void sync_Arb_IDs(void);
+extern void sync_Arb_IDs (void);
+extern void init_bsp_APIC (void);
 extern void setup_local_APIC (void);
-extern void init_apic_mappings(void);
-extern void smp_local_timer_interrupt(struct pt_regs * regs);
-extern void setup_APIC_clocks(void);
-#endif
+extern void init_apic_mappings (void);
+extern void smp_local_timer_interrupt (struct pt_regs * regs);
+extern void setup_APIC_clocks (void);
+extern void setup_apic_nmi_watchdog (void);
+extern inline void nmi_watchdog_tick (struct pt_regs * regs);
+extern int APIC_init_uniprocessor (void);
 
-#endif
+extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback);
+extern void apic_pm_unregister(struct pm_dev*);
+
+extern unsigned int apic_timer_irqs [NR_CPUS];
+extern int check_nmi_watchdog (void);
+
+extern unsigned int nmi_watchdog;
+#define NMI_NONE       0
+#define NMI_IO_APIC    1
+#define NMI_LOCAL_APIC 2
+#define NMI_INVALID    3
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#endif /* __ASM_APIC_H */
index 767e644c8b90dddf28ac8c84238a81b04f9859f6..69f1eb9a9b9674ed9970343fb6eb570129113b33 100644 (file)
@@ -130,10 +130,8 @@ static inline void io_apic_sync(unsigned int apic)
        (void) *(IO_APIC_BASE(apic)+4);
 }
 
-extern int nmi_watchdog;
 /* 1 if "noapic" boot option passed */
 extern int skip_ioapic_setup;
-extern void IO_APIC_init_uniprocessor (void);
 
 /*
  * If we use the IO-APIC for IRQ routing, disable automatic
index 08c96a276f04f2383e1db5f692a814d5584fd763..c0d2b88b6ff0aa35b0cc233d75ebd0abd09eb008 100644 (file)
@@ -10,6 +10,8 @@
  *     <tomsoft@informatik.tu-chemnitz.de>
  */
 
+#include <linux/config.h>
+
 #define TIMER_IRQ 0
 
 /*
@@ -33,7 +35,7 @@ extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
 
 #ifdef CONFIG_X86_LOCAL_APIC
-#define ARCH_HAS_NMI_WATCHDOG          /* See include/linux/irq.h */
+#define ARCH_HAS_NMI_WATCHDOG          /* See include/linux/nmi.h */
 #endif
 
 #endif /* _ASM_IRQ_H */
index c856efe54162440342a1c2f4ff3aaf94f80574b3..0d64a42db7b5b3ba39786d8008d31d51404ff07d 100644 (file)
@@ -182,6 +182,7 @@ extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 extern int mp_current_pci_id;
 extern unsigned long mp_lapic_addr;
 extern int pic_mode;
+extern int using_apic_timer;
 
 #endif
 
index 50a21adf4ba716aa96939f99cce75567c0508588..d660b9bfbf7e72af461530335d773d09a72f2564 100644 (file)
@@ -86,9 +86,16 @@ typedef struct { unsigned long pgprot; } pgprot_t;
  * Tell the user there is some problem. Beep too, so we can
  * see^H^H^Hhear bugs in early bootup as well!
  */
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void do_BUG(const char *file, int line);
 #define BUG() do {                                     \
-       __asm__ __volatile__(".byte 0x0f,0x0b");        \
+       do_BUG(__FILE__, __LINE__);                     \
+       __asm__ __volatile__("ud2");                    \
 } while (0)
+#else
+#define BUG() __asm__ __volatile__(".byte 0x0f,0x0b")
+#endif
 
 #define PAGE_BUG(page) do { \
        BUG(); \
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
new file mode 100644 (file)
index 0000000..05205c7
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __LINUX_COMPILER_H
+#define __LINUX_COMPILER_H
+
+/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented
+   a mechanism by which the user can annotate likely branch directions and
+   expect the blocks to be reordered appropriately.  Define __builtin_expect
+   to nothing for earlier compilers.  */
+
+#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x)      __builtin_expect((x),1)
+#define unlikely(x)    __builtin_expect((x),0)
+
+#endif /* __LINUX_COMPILER_H */
index 22ebd781b305548206d4eee2ca9ae63382e82b70..f39bf2502871c110aa82e6daa1a8c351985fe608 100644 (file)
@@ -16,8 +16,10 @@ typedef __u64        Elf64_Addr;
 typedef __u16  Elf64_Half;
 typedef __s16  Elf64_SHalf;
 typedef __u64  Elf64_Off;
-typedef __s64  Elf64_Sword;
-typedef __u64  Elf64_Word;
+typedef __s32  Elf64_Sword;
+typedef __u32  Elf64_Word;
+typedef __u64  Elf64_Xword;
+typedef __s64  Elf64_Sxword;
 
 /* These constants are for the segment types stored in the image headers */
 #define PT_NULL    0
@@ -65,6 +67,7 @@ typedef __u64 Elf64_Word;
 #define EM_SPARC32PLUS 18      /* Sun's "v8plus" */
 
 #define EM_PPC        20       /* PowerPC */
+#define EM_PPC64       21       /* PowerPC64 */
 
 #define EM_SH         42       /* SuperH */
 
@@ -180,10 +183,10 @@ typedef struct dynamic{
 } Elf32_Dyn;
 
 typedef struct {
-  Elf64_Word d_tag;            /* entry tag value */
+  Elf64_Sxword d_tag;          /* entry tag value */
   union {
-    Elf64_Word d_val;
-    Elf64_Word d_ptr;
+    Elf64_Xword d_val;
+    Elf64_Addr d_ptr;
   } d_un;
 } Elf64_Dyn;
 
@@ -229,7 +232,7 @@ typedef struct {
 #define R_MIPS_GOT_PAGE                20
 #define R_MIPS_GOT_OFST                21
 /*
- * The following two relocation types are specified in the the MIPS ABI
+ * The following two relocation types are specified in the MIPS ABI
  * conformance guide version 1.2 but not yet in the psABI.
  */
 #define R_MIPS_GOTHI16         22
@@ -241,7 +244,7 @@ typedef struct {
 #define R_MIPS_HIGHER          28
 #define R_MIPS_HIGHEST         29
 /*
- * The following two relocation types are specified in the the MIPS ABI
+ * The following two relocation types are specified in the MIPS ABI
  * conformance guide version 1.2 but not yet in the psABI.
  */
 #define R_MIPS_CALLHI16                30
@@ -374,7 +377,7 @@ typedef struct elf32_rel {
 
 typedef struct elf64_rel {
   Elf64_Addr r_offset; /* Location at which to apply the action */
-  Elf64_Word r_info;   /* index and type of relocation */
+  Elf64_Xword r_info;  /* index and type of relocation */
 } Elf64_Rel;
 
 typedef struct elf32_rela{
@@ -385,8 +388,8 @@ typedef struct elf32_rela{
 
 typedef struct elf64_rela {
   Elf64_Addr r_offset; /* Location at which to apply the action */
-  Elf64_Word r_info;   /* index and type of relocation */
-  Elf64_Word r_addend; /* Constant addend used to compute value */
+  Elf64_Xword r_info;  /* index and type of relocation */
+  Elf64_Sxword r_addend;       /* Constant addend used to compute value */
 } Elf64_Rela;
 
 typedef struct elf32_sym{
@@ -399,12 +402,12 @@ typedef struct elf32_sym{
 } Elf32_Sym;
 
 typedef struct elf64_sym {
-  Elf32_Word st_name;          /* Symbol name, index in string tbl (yes, Elf32) */
+  Elf64_Word st_name;          /* Symbol name, index in string tbl */
   unsigned char        st_info;        /* Type and binding attributes */
   unsigned char        st_other;       /* No defined meaning, 0 */
   Elf64_Half st_shndx;         /* Associated section index */
   Elf64_Addr st_value;         /* Value of the symbol */
-  Elf64_Word st_size;          /* Associated symbol size */
+  Elf64_Xword st_size;         /* Associated symbol size */
 } Elf64_Sym;
 
 
@@ -429,19 +432,19 @@ typedef struct elf32_hdr{
 
 typedef struct elf64_hdr {
   unsigned char        e_ident[16];            /* ELF "magic number" */
-  Elf64_SHalf e_type;
+  Elf64_Half e_type;
   Elf64_Half e_machine;
-  __s32 e_version;
+  Elf64_Word e_version;
   Elf64_Addr e_entry;          /* Entry point virtual address */
   Elf64_Off e_phoff;           /* Program header table file offset */
   Elf64_Off e_shoff;           /* Section header table file offset */
-  __s32 e_flags;
-  Elf64_SHalf e_ehsize;
-  Elf64_SHalf e_phentsize;
-  Elf64_SHalf e_phnum;
-  Elf64_SHalf e_shentsize;
-  Elf64_SHalf e_shnum;
-  Elf64_SHalf e_shstrndx;
+  Elf64_Word e_flags;
+  Elf64_Half e_ehsize;
+  Elf64_Half e_phentsize;
+  Elf64_Half e_phnum;
+  Elf64_Half e_shentsize;
+  Elf64_Half e_shnum;
+  Elf64_Half e_shstrndx;
 } Elf64_Ehdr;
 
 /* These constants define the permissions on sections in the program
@@ -462,14 +465,14 @@ typedef struct elf32_phdr{
 } Elf32_Phdr;
 
 typedef struct elf64_phdr {
-  __s32 p_type;
-  __s32 p_flags;
+  Elf64_Word p_type;
+  Elf64_Word p_flags;
   Elf64_Off p_offset;          /* Segment file offset */
   Elf64_Addr p_vaddr;          /* Segment virtual address */
   Elf64_Addr p_paddr;          /* Segment physical address */
-  Elf64_Word p_filesz;         /* Segment size in file */
-  Elf64_Word p_memsz;          /* Segment size in memory */
-  Elf64_Word p_align;          /* Segment alignment, file & memory */
+  Elf64_Xword p_filesz;                /* Segment size in file */
+  Elf64_Xword p_memsz;         /* Segment size in memory */
+  Elf64_Xword p_align;         /* Segment alignment, file & memory */
 } Elf64_Phdr;
 
 /* sh_type */
@@ -526,16 +529,16 @@ typedef struct {
 } Elf32_Shdr;
 
 typedef struct elf64_shdr {
-  Elf32_Word sh_name;          /* Section name, index in string tbl (yes Elf32) */
-  Elf32_Word sh_type;          /* Type of section (yes Elf32) */
-  Elf64_Word sh_flags;         /* Miscellaneous section attributes */
+  Elf64_Word sh_name;          /* Section name, index in string tbl */
+  Elf64_Word sh_type;          /* Type of section */
+  Elf64_Xword sh_flags;                /* Miscellaneous section attributes */
   Elf64_Addr sh_addr;          /* Section virtual addr at execution */
   Elf64_Off sh_offset;         /* Section file offset */
-  Elf64_Word sh_size;          /* Size of section in bytes */
-  Elf32_Word sh_link;          /* Index of another section (yes Elf32) */
-  Elf32_Word sh_info;          /* Additional section information (yes Elf32) */
-  Elf64_Word sh_addralign;     /* Section alignment */
-  Elf64_Word sh_entsize;       /* Entry size if section holds table */
+  Elf64_Xword sh_size;         /* Size of section in bytes */
+  Elf64_Word sh_link;          /* Index of another section */
+  Elf64_Word sh_info;          /* Additional section information */
+  Elf64_Xword sh_addralign;    /* Section alignment */
+  Elf64_Xword sh_entsize;      /* Entry size if section holds table */
 } Elf64_Shdr;
 
 #define        EI_MAG0         0               /* e_ident[] indexes */
@@ -582,15 +585,10 @@ typedef struct elf32_note {
 } Elf32_Nhdr;
 
 /* Note header in a PT_NOTE section */
-/*
- * For now we use the 32 bit version of the structure until we figure
- * out whether we need anything better.  Note - on the Alpha, "unsigned int"
- * is only 32 bits.
- */
 typedef struct elf64_note {
-  Elf32_Word n_namesz; /* Name size */
-  Elf32_Word n_descsz; /* Content size */
-  Elf32_Word n_type;   /* Content type */
+  Elf64_Word n_namesz; /* Name size */
+  Elf64_Word n_descsz; /* Content size */
+  Elf64_Word n_type;   /* Content type */
 } Elf64_Nhdr;
 
 #if ELF_CLASS == ELFCLASS32
index fca74da7d54ba73baa7ec5d1acdaa2e554d2e76f..ddc03d638675e5194d2ef72afca996bd99d532c5 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef __irq_h
 #define __irq_h
 
+/*
+ * Please do not include this file in generic code.  There is currently
+ * no requirement for any architecture to implement anything held
+ * within this file.
+ *
+ * Thanks. --rmk
+ */
+
+#include <linux/config.h>
+
+#if !defined(CONFIG_ARCH_S390)
+
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 
@@ -56,23 +68,12 @@ extern irq_desc_t irq_desc [NR_IRQS];
 
 #include <asm/hw_irq.h> /* the arch dependent stuff */
 
-/**
- * touch_nmi_watchdog - restart NMI watchdog timeout.
- * 
- * If the architecture supports the NMI watchdog, touch_nmi_watchdog()
- * may be used to reset the timeout - for code which intentionally
- * disables interrupts for a long time. This call is stateless.
- */
-#ifdef ARCH_HAS_NMI_WATCHDOG
-extern void touch_nmi_watchdog(void);
-#else
-# define touch_nmi_watchdog() do { } while(0)
-#endif
-
 extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
 extern int setup_irq(unsigned int , struct irqaction * );
 
 extern hw_irq_controller no_irq_type;  /* needed in every arch ? */
 extern void no_action(int cpl, void *dev_id, struct pt_regs *regs);
 
+#endif
+
 #endif /* __asm_h */
index 4a88363eeca4650139bc9eb7097efc3efbbf179f..81c9170a0f3a0890ced9e8fb5ea9734084a97e63 100644 (file)
@@ -153,6 +153,16 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea
        for (pos = (head)->next, prefetch(pos->next); pos != (head); \
                pos = pos->next, prefetch(pos->next))
                
+/**
+ * list_for_each_safe  -       iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
 #endif /* __KERNEL__ || _LVM_H_INCLUDE */
 
 #endif
index e46f28eee6bbc0d6b9ce76d06365f1ad823d45c4..1f2930e3944c4c1556a132767b223822a0162b6a 100644 (file)
 #define COMPAQ_CISS_MAJOR6      110
 #define COMPAQ_CISS_MAJOR7      111
 
+#define ATARAID_MAJOR          114
+
 #define DASD_MAJOR      94     /* Official assignations from Peter */
 
 #define MDISK_MAJOR     95     /* Official assignations from Peter */
index 1efd8c8b1fd28bd8036dbe48b0284a2c9b18f94a..48f0831d62f65cd182d60ef6cab17eb81558dcd5 100644 (file)
@@ -438,6 +438,8 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
 extern int ptrace_attach(struct task_struct *tsk);
+extern int ptrace_detach(struct task_struct *, unsigned int);
+extern void ptrace_disable(struct task_struct *);
 
 /*
  * On a two-level page table, this ends up being trivial. Thus the
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
new file mode 100644 (file)
index 0000000..c8f4d2f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *  linux/include/linux/nmi.h
+ */
+#ifndef LINUX_NMI_H
+#define LINUX_NMI_H
+
+#include <asm/irq.h>
+
+/**
+ * touch_nmi_watchdog - restart NMI watchdog timeout.
+ * 
+ * If the architecture supports the NMI watchdog, touch_nmi_watchdog()
+ * may be used to reset the timeout - for code which intentionally
+ * disables interrupts for a long time. This call is stateless.
+ */
+#ifdef ARCH_HAS_NMI_WATCHDOG
+extern void touch_nmi_watchdog(void);
+#else
+# define touch_nmi_watchdog() do { } while(0)
+#endif
+
+#endif
index 43186de10f0e355669f8fa43f839d9731274d268..ede11cc972f307ffd96a8a8f6ef1bb13aa5511ef 100644 (file)
@@ -746,6 +746,7 @@ extern int pci_pci_problems;
 #define PCIPCI_TRITON          2
 #define PCIPCI_NATOMA          4
 #define PCIPCI_VIAETBF         8
+#define PCIPCI_VSFX            16
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
index 0aaed1fd99db082691c1cf8c0f8738ccb50f7deb..8d7d3ffeb4818d6d566dc27c4a79cdcead327f8d 100644 (file)
@@ -54,7 +54,7 @@ static inline void prefetchw(const void *x) {;}
 #endif
 
 #ifndef PREFETCH_STRIDE
-#define PREFETCH_STRIDE (4*L1_CACHE_BYTE)
+#define PREFETCH_STRIDE (4*L1_CACHE_BYTES)
 #endif
 
 #endif
index b964abb8c5408c9812c9ba9c2e0ed26e3c0f6c89..45ab381f26aa1b47a3fb519d61d1c4b708514d78 100644 (file)
@@ -425,6 +425,7 @@ struct task_struct {
 #define PT_TRACESYS    0x00000002
 #define PT_DTRACE      0x00000004      /* delayed trace (used on m68k, i386) */
 #define PT_TRACESYSGOOD        0x00000008
+#define PT_PTRACE_CAP  0x00000010      /* ptracer can follow suid-exec */
 
 /*
  * Limit the stack by to some sane default: root can always
index 63523dce1d0c30485105efe2babc8105e1572a53..3d34e45883a8ec2796744e9ec58f22b200e931da 100644 (file)
@@ -121,6 +121,7 @@ enum
        KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */
        KERN_S390_USER_DEBUG_LOGGING=51,  /* int: dumps of user faults */
        KERN_CORE_USES_PID=52,          /* int: use core or core.%pid */
+       KERN_CADPID=54,         /* int: PID of the process to notify on CAD */
 };
 
 
index e630aba706f5806faaba20746abccdc5a430477d..de03136e551ab25b7cf85d2f88f14d4ab931efae 100644 (file)
@@ -5,6 +5,10 @@
  *     Linux Magic System Request Key Hacks
  *
  *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ *     overhauled to use key registration
+ *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
  */
 
 #include <linux/config.h>
@@ -13,12 +17,79 @@ struct pt_regs;
 struct kbd_struct;
 struct tty_struct;
 
+struct sysrq_key_op {
+       void (*handler)(int, struct pt_regs *,
+                       struct kbd_struct *, struct tty_struct *);
+       char *help_msg;
+       char *action_msg;
+};
+
 /* Generic SysRq interface -- you may call it from any device driver, supplying
  * ASCII code of the key, pointer to registers and kbd/tty structs (if they
  * are available -- else NULL's).
  */
 
-void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+void handle_sysrq(int, struct pt_regs *,
+               struct kbd_struct *, struct tty_struct *);
+
+
+/* 
+ * Nonlocking version of handle sysrq, used by sysrq handlers that need to
+ * call sysrq handlers
+ */
+
+void __handle_sysrq_nolock(int, struct pt_regs *,
+                struct kbd_struct *, struct tty_struct *);
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+
+/*
+ * Sysrq registration manipulation functions
+ */
+
+void __sysrq_lock_table (void);
+void __sysrq_unlock_table (void);
+struct sysrq_key_op *__sysrq_get_key_op (int key);
+void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p);
+
+extern __inline__ int
+__sysrq_swap_key_ops_nolock(int key, struct sysrq_key_op *insert_op_p,
+                               struct sysrq_key_op *remove_op_p) {
+       int retval;
+       if (__sysrq_get_key_op(key) == remove_op_p) {
+               __sysrq_put_key_op(key, insert_op_p);
+               retval = 0;
+       } else {
+                retval = -1;
+       }
+       return retval;
+}
+
+extern __inline__ int
+__sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+                               struct sysrq_key_op *remove_op_p) {
+       int retval;
+       __sysrq_lock_table();
+       retval = __sysrq_swap_key_ops_nolock(key, insert_op_p, remove_op_p);
+       __sysrq_unlock_table();
+       return retval;
+}
+       
+static inline int register_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, op_p, NULL);
+}
+
+static inline int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, NULL, op_p);
+}
+
+#else
+#define register_sysrq_key(a,b)                do {} while(0)
+#define unregister_sysrq_key(a,b)      do {} while(0)
+#endif
 
 /* Deferred actions */
 
index 9179e235dfe5d2018f2c5a5e65e37ada9cf2284a..91aeda9ef59139898713ca9cd559a31e3789c109 100644 (file)
@@ -72,7 +72,7 @@ void __init fork_init(unsigned long mempages)
         * value: the thread structures can take up at most half
         * of memory.
         */
-       max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 16;
+       max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8;
 
        init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
        init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
index 2b95bad07d92d9b36edd0a820e0d59f924310624..b9cf12d4c02d65de7d2b15c9a102f41ee6e36536 100644 (file)
@@ -42,6 +42,8 @@ int ptrace_attach(struct task_struct *task)
 
        /* Go */
        task->ptrace |= PT_PTRACED;
+       if (capable(CAP_SYS_PTRACE))
+               task->ptrace |= PT_PTRACE_CAP;
        task_unlock(task);
 
        write_lock_irq(&tasklist_lock);
@@ -60,6 +62,27 @@ bad:
        return -EPERM;
 }
 
+int ptrace_detach(struct task_struct *child, unsigned int data)
+{
+       if ((unsigned long) data > _NSIG)
+               return  -EIO;
+
+       /* Architecture-specific hardware disable .. */
+       ptrace_disable(child);
+
+       /* .. re-parent .. */
+       child->ptrace = 0;
+       child->exit_code = data;
+       write_lock_irq(&tasklist_lock);
+       REMOVE_LINKS(child);
+       child->p_pptr = child->p_opptr;
+       SET_LINKS(child);
+       write_unlock_irq(&tasklist_lock);
+
+       /* .. and wake it up. */
+       wake_up_process(child);
+       return 0;
+}
 
 /*
  * Access another process' address space, one page at a time.
index 3d7c4659bb752d4f674e32758c6f63edd17fdc37..3e209c8c9cc685c28a6e71b410836b4145ed38d3 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/nmi.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/completion.h>
@@ -536,6 +537,7 @@ asmlinkage void schedule(void)
        struct list_head *tmp;
        int this_cpu, c;
 
+
        spin_lock_prefetch(&runqueue_lock);
 
        if (!current->active_mm) BUG();
@@ -723,18 +725,16 @@ scheduling_in_interrupt:
 static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
                                     int nr_exclusive, const int sync)
 {
-       struct list_head *tmp, *head;
+       struct list_head *tmp;
        struct task_struct *p;
 
        CHECK_MAGIC_WQHEAD(q);
-       head = &q->task_list;
-       WQ_CHECK_LIST_HEAD(head);
-       tmp = head->next;
-       while (tmp != head) {
+       WQ_CHECK_LIST_HEAD(&q->task_list);
+       
+       list_for_each(tmp,&q->task_list) {
                unsigned int state;
                 wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
 
-               tmp = tmp->next;
                CHECK_MAGIC(curr->__magic);
                p = curr->task;
                state = p->state;
@@ -1054,7 +1054,7 @@ asmlinkage long sys_sched_yield(void)
 #if CONFIG_SMP
        int i;
 
-       // Substract non-idle processes running on other CPUs.
+       // Subtract non-idle processes running on other CPUs.
        for (i = 0; i < smp_num_cpus; i++) {
                int cpu = cpu_logical_map(i);
                if (aligned_data[cpu].schedule_data.curr != idle_task(cpu))
index 6506490a9357acd2d97225b33301e8a69f7b57c1..765761a4e71bd8d810284313f55930625f2a83c0 100644 (file)
@@ -39,6 +39,7 @@ int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;
  */
 
 int C_A_D = 1;
+int cad_pid = 1;
 
 
 /*
@@ -350,7 +351,7 @@ void ctrl_alt_del(void)
        if (C_A_D)
                schedule_task(&cad_tq);
        else
-               kill_proc(1, SIGINT, 1);
+               kill_proc(cad_pid, SIGINT, 1);
 }
        
 
index af54f02302b77d82bbf30420f8873b887c6ff213..3378b95d209cdb4543951c1d75b9ef037e69bd0c 100644 (file)
@@ -48,6 +48,7 @@ extern int max_threads;
 extern int nr_queued_signals, max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
+extern int cad_pid;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -233,6 +234,8 @@ static ctl_table kern_table[] = {
        {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
         0644, NULL, &proc_dointvec},
 #endif  
+       {KERN_CADPID, "cad_pid", &cad_pid, sizeof (int),
+        0600, NULL, &proc_dointvec},
        {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
         0644, NULL, &proc_dointvec},
        {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
index a34bdab16490accdcc1a94075aa7154ca011ecab..af3847533cabfec8bfb18b87a33c992e51149ab4 100644 (file)
@@ -344,7 +344,8 @@ void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsign
        /*
         * Whoops, we cannot satisfy the allocation request.
         */
-       BUG();
+       printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+       panic("Out of memory");
        return NULL;
 }
 
index 3b5d92903c5e972dd2603134a0c8b0540faef0a2..b6c75572fe100c96475893a5817cfd06fe058749 100644 (file)
@@ -273,6 +273,13 @@ static inline void bounce_end_io (struct buffer_head *bh, int uptodate)
 
 static __init int init_emergency_pool(void)
 {
+       struct sysinfo i;
+        si_meminfo(&i);
+        si_swapinfo(&i);
+        
+        if (!i.totalhigh)
+               return 0;
+
        spin_lock_irq(&emergency_lock);
        while (nr_emergency_pages < POOL_SIZE) {
                struct page * page = alloc_page(GFP_ATOMIC);
index 30ffea7676342b6f4c547f15ae87352f7096a038..f8859ede3f05ca0e5b51923377399e2026a0a653 100644 (file)
@@ -103,8 +103,10 @@ static inline void free_one_pgd(pgd_t * dir)
        }
        pmd = pmd_offset(dir, 0);
        pgd_clear(dir);
-       for (j = 0; j < PTRS_PER_PMD ; j++)
+       for (j = 0; j < PTRS_PER_PMD ; j++) {
+               prefetchw(pmd+j+(PREFETCH_STRIDE/16));
                free_one_pmd(pmd+j);
+       }
        pmd_free(pmd);
 }
 
index 9f1f3125630a10f79e87984858048e931a28f4ed..779c4af4f8e811ccd46451337a74851a727ca649 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
+#include <linux/compiler.h>
 
 int nr_swap_pages;
 int nr_active_pages;
@@ -253,7 +254,7 @@ static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask
 
                local_pages = &current->local_pages;
 
-               if (__freed) {
+               if (likely(__freed)) {
                        /* pick from the last inserted so we're lifo */
                        entry = local_pages->next;
                        do {
@@ -372,19 +373,21 @@ struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_
                return page;
 
        zone = zonelist->zones;
-       if (__builtin_expect(freed, 1)) {
+       if (likely(freed)) {
                for (;;) {
                        zone_t *z = *(zone++);
                        if (!z)
                                break;
 
-                       if (zone_free_pages(z, order) > (gfp_mask & __GFP_HIGH ? z->pages_min / 2 : z->pages_min)) {
-                               page = rmqueue(z, order);
-                               if (page)
-                                       return page;
-                       }
+                       page = rmqueue(z, order);
+                       if (page)
+                               return page;
                }
        } else {
+               /* 
+                * Check that no other task is been killed meanwhile,
+                * in such a case we can succeed the allocation.
+                */
                for (;;) {
                        zone_t *z = *(zone++);
                        if (!z)
@@ -683,6 +686,7 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
                zone->lock = SPIN_LOCK_UNLOCKED;
                zone->zone_pgdat = pgdat;
                zone->free_pages = 0;
+               zone->need_balance = 0;
                if (!size)
                        continue;
 
index 1b61746e3f15645cd528cf00cd6b5b410ead110e..ddad315b6a2f476aa4f9d73d7e55ffd6b987a975 100644 (file)
@@ -78,7 +78,15 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
        if (!wait) {
                SetPageDecrAfter(page);
                atomic_inc(&nr_async_pages);
-       }
+       } else
+               /*
+                * Must hold a reference until after wait_on_page()
+                * returned or it could be freed by the VM after
+                * I/O is completed and the page is been unlocked.
+                * The asynchronous path is fine since it never
+                * references the page after brw_page().
+                */
+               page_cache_get(page);
 
        /* block_size == PAGE_SIZE/zones_used */
        brw_page(rw, page, dev, zones, block_size);
@@ -94,6 +102,7 @@ static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page)
        /* This shouldn't happen, but check to be sure. */
        if (page_count(page) == 0)
                printk(KERN_ERR "rw_swap_page: page unused while waiting!\n");
+       page_cache_release(page);
 
        return 1;
 }
index e7bf381df8499fa9b4b6cb1917018036869eeaea..f12bd6064430f0f33b1b38feb4d51aac897c5757 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -72,6 +72,7 @@
 #include       <linux/slab.h>
 #include       <linux/interrupt.h>
 #include       <linux/init.h>
+#include       <linux/compiler.h>
 #include       <asm/uaccess.h>
 
 /*
@@ -1230,7 +1231,7 @@ static inline void * kmem_cache_alloc_one_tail (kmem_cache_t *cachep,
        objp = slabp->s_mem + slabp->free*cachep->objsize;
        slabp->free=slab_bufctl(slabp)[slabp->free];
 
-       if (__builtin_expect(slabp->free == BUFCTL_END, 0)) {
+       if (unlikely(slabp->free == BUFCTL_END)) {
                list_del(&slabp->list);
                list_add(&slabp->list, &cachep->slabs_full);
        }
@@ -1264,11 +1265,11 @@ static inline void * kmem_cache_alloc_one_tail (kmem_cache_t *cachep,
                                                                \
        slabs_partial = &(cachep)->slabs_partial;               \
        entry = slabs_partial->next;                            \
-       if (__builtin_expect(entry == slabs_partial, 0)) {      \
+       if (unlikely(entry == slabs_partial)) {                 \
                struct list_head * slabs_free;                  \
                slabs_free = &(cachep)->slabs_free;             \
                entry = slabs_free->next;                       \
-               if (__builtin_expect(entry == slabs_free, 0))   \
+               if (unlikely(entry == slabs_free))              \
                        goto alloc_new_slab;                    \
                list_del(entry);                                \
                list_add(entry, slabs_partial);                 \
@@ -1291,11 +1292,11 @@ void* kmem_cache_alloc_batch(kmem_cache_t* cachep, int flags)
                /* Get slab alloc is to come from. */
                slabs_partial = &(cachep)->slabs_partial;
                entry = slabs_partial->next;
-               if (__builtin_expect(entry == slabs_partial, 0)) {
+               if (unlikely(entry == slabs_partial)) {
                        struct list_head * slabs_free;
                        slabs_free = &(cachep)->slabs_free;
                        entry = slabs_free->next;
-                       if (__builtin_expect(entry == slabs_free, 0))
+                       if (unlikely(entry == slabs_free))
                                break;
                        list_del(entry);
                        list_add(entry, slabs_partial);
@@ -1436,11 +1437,11 @@ static inline void kmem_cache_free_one(kmem_cache_t *cachep, void *objp)
        /* fixup slab chains */
        {
                int inuse = slabp->inuse;
-               if (__builtin_expect(!--slabp->inuse, 0)) {
+               if (unlikely(!--slabp->inuse)) {
                        /* Was partial or full, now empty. */
                        list_del(&slabp->list);
                        list_add(&slabp->list, &cachep->slabs_free);
-               } else if (__builtin_expect(inuse == cachep->num, 0)) {
+               } else if (unlikely(inuse == cachep->num)) {
                        /* Was full. */
                        list_del(&slabp->list);
                        list_add(&slabp->list, &cachep->slabs_partial);
index 37b9ea1babb6ec497a40cc0b02a0b5a8daacf808..18b504deb45c7329152c16b0ed06ed9e7d959522 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -54,6 +54,7 @@ void deactivate_page_nolock(struct page * page)
                del_page_from_active_list(page);
                add_page_to_inactive_list(page);
        }
+       ClearPageReferenced(page);
 }      
 
 void deactivate_page(struct page * page)
@@ -72,6 +73,7 @@ void activate_page_nolock(struct page * page)
                del_page_from_inactive_list(page);
                add_page_to_active_list(page);
        }
+       SetPageReferenced(page);
 }
 
 void activate_page(struct page * page)
index 9bb4dbcba7194de8e5a7b6b84cefd04035ee6bf1..2dabce18f263224ad57add7cfe22a4ed88de89a9 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
+#include <linux/compiler.h>
 
 #include <asm/pgalloc.h>
 
@@ -46,20 +47,24 @@ static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct*
 {
        pte_t pte;
        swp_entry_t entry;
+       int right_classzone;
 
        /* Don't look at this pte if it's been accessed recently. */
        if (ptep_test_and_clear_young(page_table)) {
                flush_tlb_page(vma, address);
-               SetPageReferenced(page);
+               activate_page(page);
                return 0;
        }
-
-       if (!memclass(page->zone, classzone))
+       if ((PageInactive(page) || PageActive(page)) && PageReferenced(page))
                return 0;
 
        if (TryLockPage(page))
                return 0;
 
+       right_classzone = 1;
+       if (!memclass(page->zone, classzone))
+               right_classzone = 0;
+
        /* From this point on, the odds are that we're going to
         * nuke this pte, so read and clear the pte.  This hook
         * is needed on CPUs which update the accessed and dirty
@@ -89,7 +94,7 @@ drop_pte:
                        if (freeable)
                                deactivate_page(page);
                        page_cache_release(page);
-                       return freeable;
+                       return freeable & right_classzone;
                }
        }
 
@@ -292,8 +297,10 @@ static int swap_out(unsigned int priority, zone_t * classzone, unsigned int gfp_
        /* Then, look at the other mm's */
        counter = mmlist_nr / priority;
        do {
-               if (current->need_resched)
+               if (unlikely(current->need_resched)) {
+                       __set_current_state(TASK_RUNNING);
                        schedule();
+               }
 
                spin_lock(&mmlist_lock);
                mm = swap_mm;
@@ -323,20 +330,19 @@ empty:
        return 0;
 }
 
-static int FASTCALL(shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zone_t * classzone, unsigned int gfp_mask));
-static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zone_t * classzone, unsigned int gfp_mask)
+static int FASTCALL(shrink_cache(struct list_head * lru, int * max_scan, int this_max_scan, int nr_pages, zone_t * classzone, unsigned int gfp_mask));
+static int shrink_cache(struct list_head * lru, int * max_scan, int this_max_scan, int nr_pages, zone_t * classzone, unsigned int gfp_mask)
 {
-       LIST_HEAD(active_local_lru);
-       LIST_HEAD(inactive_local_lru);
        struct list_head * entry;
        int __max_scan = *max_scan;
 
        spin_lock(&pagemap_lru_lock);
-       while (__max_scan && (entry = lru->prev) != lru) {
+       while (__max_scan && this_max_scan && (entry = lru->prev) != lru) {
                struct page * page;
 
-               if (__builtin_expect(current->need_resched, 0)) {
+               if (unlikely(current->need_resched)) {
                        spin_unlock(&pagemap_lru_lock);
+                       __set_current_state(TASK_RUNNING);
                        schedule();
                        spin_lock(&pagemap_lru_lock);
                        continue;
@@ -344,26 +350,38 @@ static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zo
 
                page = list_entry(entry, struct page, lru);
 
-               if (__builtin_expect(!PageInactive(page) && !PageActive(page), 0))
+               if (unlikely(!PageInactive(page) && !PageActive(page)))
                        BUG();
 
+               this_max_scan--;
+
                if (PageTestandClearReferenced(page)) {
-                       if (PageInactive(page)) {
-                               del_page_from_inactive_list(page);
-                               add_page_to_active_list(page);
-                       } else if (PageActive(page)) {
+                       if (!PageSwapCache(page)) {
+                               if (PageInactive(page)) {
+                                       del_page_from_inactive_list(page);
+                                       add_page_to_active_list(page);
+                               } else if (PageActive(page)) {
+                                       list_del(entry);
+                                       list_add(entry, &active_list);
+                               } else
+                                       BUG();
+                       } else {
                                list_del(entry);
-                               list_add(entry, &active_list);
-                       } else
-                               BUG();
+                               list_add(entry, lru);
+                       }
                        continue;
                }
 
-               deactivate_page_nolock(page);
-               list_del(entry);
-               list_add_tail(entry, &inactive_local_lru);
+               if (PageInactive(page)) {
+                       /* just roll it over, no need to update any stat */
+                       list_del(entry);
+                       list_add(entry, &inactive_list);
+               } else {
+                       del_page_from_active_list(page);
+                       add_page_to_inactive_list(page);
+               }
 
-               if (__builtin_expect(!memclass(page->zone, classzone), 0))
+               if (unlikely(!memclass(page->zone, classzone)))
                        continue;
 
                __max_scan--;
@@ -371,8 +389,6 @@ static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zo
                /* Racy check to avoid trylocking when not worthwhile */
                if (!page->buffers && page_count(page) != 1) {
                        activate_page_nolock(page);
-                       list_del(entry);
-                       list_add_tail(entry, &active_local_lru);
                        continue;
                }
 
@@ -380,7 +396,7 @@ static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zo
                 * The page is locked. IO in progress?
                 * Move it to the back of the list.
                 */
-               if (__builtin_expect(TryLockPage(page), 0))
+               if (unlikely(TryLockPage(page)))
                        continue;
 
                if (PageDirty(page) && is_page_cache_freeable(page)) {
@@ -456,10 +472,10 @@ static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zo
                        }
                }
 
-               if (__builtin_expect(!page->mapping, 0))
+               if (unlikely(!page->mapping))
                        BUG();
 
-               if (__builtin_expect(!spin_trylock(&pagecache_lock), 0)) {
+               if (unlikely(!spin_trylock(&pagecache_lock))) {
                        /* we hold the page lock so the page cannot go away from under us */
                        spin_unlock(&pagemap_lru_lock);
 
@@ -479,7 +495,7 @@ static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zo
                }
 
                /* point of no return */
-               if (__builtin_expect(!PageSwapCache(page), 1))
+               if (likely(!PageSwapCache(page)))
                        __remove_inode_page(page);
                else
                        __delete_from_swap_cache(page);
@@ -496,29 +512,48 @@ static int shrink_cache(struct list_head * lru, int * max_scan, int nr_pages, zo
                        continue;
                break;
        }
-
-       list_splice(&inactive_local_lru, &inactive_list);
-       list_splice(&active_local_lru, &active_list);
        spin_unlock(&pagemap_lru_lock);
 
        *max_scan = __max_scan;
        return nr_pages;
 }
 
+static void refill_inactive(int nr_pages)
+{
+       struct list_head * entry;
+
+       spin_lock(&pagemap_lru_lock);
+       entry = active_list.prev;
+       while (nr_pages-- && entry != &active_list) {
+               struct page * page;
+
+               page = list_entry(entry, struct page, lru);
+               entry = entry->prev;
+
+               if (!page->buffers && page_count(page) != 1)
+                       continue;
+
+               del_page_from_active_list(page);
+               add_page_to_inactive_list(page);
+       }
+       spin_unlock(&pagemap_lru_lock);
+}
+
 static int FASTCALL(shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask, int nr_pages));
 static int shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask, int nr_pages)
 {
-       int max_scan = (nr_inactive_pages + nr_active_pages / priority) / priority;
+       int max_scan = (nr_inactive_pages + nr_active_pages / DEF_PRIORITY) / priority;
 
        nr_pages -= kmem_cache_reap(gfp_mask);
        if (nr_pages <= 0)
                return 0;
 
-       nr_pages = shrink_cache(&inactive_list, &max_scan, nr_pages, classzone, gfp_mask);
+       refill_inactive(nr_pages / 2);
+       nr_pages = shrink_cache(&inactive_list, &max_scan, nr_inactive_pages, nr_pages, classzone, gfp_mask);
        if (nr_pages <= 0)
                return 0;
 
-       nr_pages = shrink_cache(&active_list, &max_scan, nr_pages, classzone, gfp_mask);
+       nr_pages = shrink_cache(&active_list, &max_scan, nr_active_pages / DEF_PRIORITY, nr_pages, classzone, gfp_mask);
        if (nr_pages <= 0)
                return 0;
 
@@ -531,6 +566,7 @@ static int shrink_caches(int priority, zone_t * classzone, unsigned int gfp_mask
 int try_to_free_pages(zone_t * classzone, unsigned int gfp_mask, unsigned int order)
 {
        int priority = DEF_PRIORITY;
+       int ret = 0;
 
        do {
                int nr_pages = SWAP_CLUSTER_MAX;
@@ -538,10 +574,10 @@ int try_to_free_pages(zone_t * classzone, unsigned int gfp_mask, unsigned int or
                if (nr_pages <= 0)
                        return 1;
 
-               swap_out(priority, classzone, gfp_mask, SWAP_CLUSTER_MAX);
+               ret |= swap_out(priority, classzone, gfp_mask, SWAP_CLUSTER_MAX << 2);
        } while (--priority);
 
-       return 0;
+       return ret;
 }
 
 DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
@@ -566,12 +602,14 @@ static int kswapd_balance_pgdat(pg_data_t * pgdat)
 
        for (i = pgdat->nr_zones-1; i >= 0; i--) {
                zone = pgdat->node_zones + i;
-               if (current->need_resched)
+               if (unlikely(current->need_resched))
                        schedule();
                if (!zone->need_balance)
                        continue;
                if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
                        zone->need_balance = 0;
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ*5);
                        continue;
                }
                if (check_classzone_need_balance(zone))
index 62aa7bd536d5ba2b014b8e0832b8a19e0aff4c29..8c93b78a5de5b381b0c2224cbddc50b1bd8d2b1c 100644 (file)
@@ -504,8 +504,6 @@ EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
 EXPORT_SYMBOL(dev_mc_delete);
 EXPORT_SYMBOL(dev_mc_upload);
-EXPORT_SYMBOL(n_tty_ioctl);
-EXPORT_SYMBOL(tty_register_ldisc);
 EXPORT_SYMBOL(__kill_fasync);
 
 EXPORT_SYMBOL(if_port_text);
diff --git a/scripts/mkspec b/scripts/mkspec
new file mode 100644 (file)
index 0000000..43ee736
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+#      Output a simple RPM spec file that uses no fancy features requring
+#      RPM v4. This is intended to work with any RPM distro.
+#
+#      The only gothic bit here is redefining install_post to avoid 
+#      stripping the symbols from files in the kernel which we want
+#
+echo "Name: kernel"
+echo "Summary: The Linux Kernel"
+echo "Version: "$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION | sed -e "s/-//"
+# we need to determine the NEXT version number so that uname and
+# rpm -q will agree
+echo "Release: `. scripts/mkversion`"
+echo "License: GPL"
+echo "Group: System Environment/Kernel"
+echo "Vendor: The Linux Community"
+echo "URL: http://www.kernel.org"
+echo -n "Source: kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL"
+echo "$EXTRAVERSION.tar.gz" | sed -e "s/-//"
+echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
+echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
+echo ""
+echo "%description"
+echo "The Linux Kernel, the operating system core itself"
+echo ""
+echo "%prep"
+echo "%setup -q"
+echo ""
+echo "%build"
+echo "make oldconfig dep clean bzImage modules"
+echo ""
+echo "%install"
+echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
+echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make modules_install'
+echo 'cp arch/i386/boot/bzImage $RPM_BUILD_ROOT'"/boot/vmlinuz-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo ""
+echo "%clean"
+echo '#echo -rf $RPM_BUILD_ROOT'
+echo ""
+echo "%files"
+echo '%defattr (-, root, root)'
+echo "%dir /lib/modules"
+echo "/lib/modules/$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo "/boot/*"
+echo ""
diff --git a/scripts/mkversion b/scripts/mkversion
new file mode 100644 (file)
index 0000000..c12addc
--- /dev/null
@@ -0,0 +1,6 @@
+if [ ! -f .version ]
+then
+    echo 1
+else
+    expr 0`cat .version` + 1
+fi