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
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
-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
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
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)
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,
+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.
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.
'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?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.)
'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...)
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 SysRQ
+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>
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 10
-EXTRAVERSION =-pre11
+EXTRAVERSION =-pre12
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
.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 \
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) \
$(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
$(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
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
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)
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:
}
}
+/*
+ * 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;
* 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;
/*
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
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;
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
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
# General setup
#
CONFIG_NET=y
-# CONFIG_VISWS is not set
CONFIG_X86_IO_APIC=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_PCI=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
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_ARM_AM79C961A is not set
# CONFIG_SUNLANCE is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNBMAC is not set
# CONFIG_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
# 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
# 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
#
# Kernel hacking
#
-# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
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
* 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>
#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, };
*/
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);
}
* 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);
}
* for 82489DX!).
*/
value = apic_read(APIC_SPIV);
- value &= ~(1<<8);
+ value &= ~APIC_SPIV_APIC_ENABLED;
apic_write_around(APIC_SPIV, value);
}
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;
/*
* Enable APIC
*/
- value |= (1<<8);
+ value |= APIC_SPIV_APIC_ENABLED;
/*
* Some unknown Intel IO/APIC (or APIC) errata is biting us with
*/
#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
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);
void __init setup_APIC_clocks (void)
{
+ printk("Using local APIC timer interrupts.\n");
+ using_apic_timer = 1;
+
__cli();
calibration_result = calibrate_APIC_clock();
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;
+}
* 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
(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)
{
/* 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;
}
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;
#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
{
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;
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.
*/
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
*/
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
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
*/
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"),
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 */
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"),
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, }
};
#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
+
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/desc.h>
+#include <asm/apic.h>
#include <linux/irq.h>
{
int i;
+#ifdef CONFIG_X86_LOCAL_APIC
+ init_bsp_APIC();
+#endif
init_8259A(0);
for (i = 0; i < NR_IRQS; i++) {
#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
printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_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)
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)
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;
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,
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
* 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
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) {
/*
*/
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;
}
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;
}
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
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 ",
* 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;
* 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.
*
}
/**
- * 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.
*/
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)
{
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)
{
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
*/
if (!(new_value & cpu_online_map))
return -EINVAL;
-#endif
irq_affinity[irq] = new_value;
irq_desc[irq].handler->set_affinity(irq, new_value);
return full_count;
}
+#endif
+
static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
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) ||
/* 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;
/* 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;
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;
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++;
}
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 */
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:
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);
*/
void __init find_smp_config (void)
{
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
find_intel_smp();
#endif
#ifdef CONFIG_VISWS
--- /dev/null
+/*
+ * 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);
+}
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) {
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++;
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.
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;
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))) {
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:
*/
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.
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
* 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;
}
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);
}
}
cycles_t cacheflush_time;
-extern unsigned long cpu_khz;
static void smp_tune_scheduling (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;
}
* 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
smp_done:
zap_low_mappings();
}
-
if (!user_mode(regs))
x86_do_profile(regs->eip);
#else
- if (!smp_found_config)
+ if (!using_apic_timer)
smp_local_timer_interrupt(regs);
#endif
show_trace(esp);
}
-static void show_registers(struct pt_regs *regs)
+void show_registers(struct pt_regs *regs)
{
int i;
int in_kernel = 1;
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.
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)
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;
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
#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()
}
}
-#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;
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)
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:
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;
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;
#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;
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:
#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.
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)
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)
#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;
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;
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;
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;
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;
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:
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;
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)
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;
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)
};
#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];
}
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;
}
};
#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];
}
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;
}
/******************************************************************************
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
*******************************************************************************
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];
MODULE_PARM(IADebugFlag, "i");
#endif
+MODULE_LICENSE("GPL");
+
#if BITS_PER_LONG != 32
# error FIXME: this driver only works on 32-bit platforms
#endif
}
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;
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) */
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++;
(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;
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 */
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);
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",
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);)
kfree(rtne);
}
ia_que_tx(iadev);
+out:
return;
}
#if 0
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;
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;
else {
IF_ERR(printk(" cause: buffer over flow\n");)
}
- free_desc(dev, desc);
- return 0;
+ goto out_free_desc;
}
/*
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
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 {
#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
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)
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
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);
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;
}
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;
}
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;
*/
/* 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;
/* 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++;
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;
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);
}
}
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",
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.
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 */
/* 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;
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 */
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;
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;
/* 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;
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))) {
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;
}
case BLKRASET:
case BLKRAGET:
case BLKPG:
+ case BLKELVGET:
+ case BLKELVSET:
return( blk_ioctl(inode->i_rdev, cmd, arg));
case CCISS_GETPCIINFO:
{
case BLKROGET:
case BLKRASET:
case BLKRAGET:
+ case BLKELVGET:
+ case BLKELVSET:
case BLKPG:
return blk_ioctl(inode->i_rdev, cmd, arg);
#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>
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
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))
#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
#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
#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>
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);
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;
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);
}
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;
return addr | agp_bridge.masks[0].mask;
}
+static void intel_resume(void)
+{
+ intel_configure();
+}
/* Setup function */
static gatt_mask intel_generic_masks[] =
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;
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;
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;
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;
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;
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;
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();
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;
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);
}
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;
&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);
"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,
"Intel",
"Generic",
intel_generic_setup },
+
#endif /* CONFIG_AGP_INTEL */
#ifdef CONFIG_AGP_SIS
"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,
"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,
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;
}
}
}
+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);
}
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");
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);
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;
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;
}
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
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;
}
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)
{
| 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.
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;
}
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);
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;
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;
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) {
}
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);
}
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);
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;
}
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;
}
/* 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 */
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) {
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;
};
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) {
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)");
#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>
#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;
{ 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 },
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_ */
*
* (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;
/* 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:
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;
}
} 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.
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);
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);
#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
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;
}
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)
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;
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)
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)
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;
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;
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));
return -ENOIOCTLCMD;
}
}
+
+EXPORT_SYMBOL(n_tty_ioctl);
*/
#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)
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
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)
--- /dev/null
+/*
+ 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);
+
--- /dev/null
+/*
+ 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);
+
--- /dev/null
+/*
+ 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);
--- /dev/null
+
+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];
+};
--- /dev/null
+/*
+ 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);
--- /dev/null
+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."
+
{
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;
/* 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 */
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,
{
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;
}
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input driver to keyboard driver binding");
+MODULE_PARM(jp_kbd_109, "i");
* - /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>
#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>
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);
#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);
}
#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;
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(¤t->sigmask_lock);
+ sigfillset(¤t->blocked);
+ flush_signals(current);
+ spin_unlock_irq(¤t->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;
}
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;
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);
case PBOOK_SLEEP_REJECT:
if (adb_got_sleep) {
adb_got_sleep = 0;
+ clear_bit(0, &adb_probe_task_flag);
adb_reset_bus();
}
break;
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;
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)
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;
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
#define ADB_MAJOR 56 /* major number for /dev/adb */
-extern void adbdev_init(void);
-
struct adbdev_state {
spinlock_t lock;
atomic_t n_pending;
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 {
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
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],
r1_buffer[3],
r1_buffer[4],
r1_buffer[5],
- 0x0d, /*r1_buffer[6],*/
+ 0x0d,
r1_buffer[7]);
adb_request(&req, NULL, ADBREQ_SYNC, 9,
0x8a,
0x1b,
0x50);
-
+
adb_request(&req, NULL, ADBREQ_SYNC, 9,
ADB_WRITEREG(id,1),
r1_buffer[0],
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));
}
}
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));
}
}
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
#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;
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");
}
+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 */
#endif /* CONFIG_AIRONET4500_ISA */
-#ifdef CONFIG_AIRONET4500_365
+#ifdef CONFIG_AIRONET4500_I365
#define port_range 0x40
}
-#endif /* CONFIG_AIRONET4500_365 */
+#endif /* CONFIG_AIRONET4500_I365 */
#ifdef MODULE
int init_module(void)
#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");
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);
awc_reset(dev);
- udelay(10000);
+ mdelay(10);
AWC_LOCK_COMMAND_ISSUING(priv);
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;
awc_interrupt_process(dev);
spin_unlock_irqrestore(&priv->interrupt_spinlock, flags);
-
- return;
}
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];
{0}
};
-struct ctl_table_header * awc_driver_sysctl_header = NULL;
+struct ctl_table_header * awc_driver_sysctl_header;
const char awc_procname[]= "awc5";
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;
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:
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;
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)) {
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.
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;
}
XXDEBUG(("bmac: all bufs freed\n"));
+ bp->opened = 0;
+
return 0;
}
struct sk_buff *skb;
unsigned long flags;
+ if (bp->sleeping)
+ return;
+
save_flags(flags); cli();
while (1) {
i = bp->tx_fill + 1;
* 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>
#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;
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;
/* 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) {
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)
unsigned long flags;
gm->sleeping = 1;
- netif_stop_queue(gm->dev);
+ netif_device_detach(gm->dev);
spin_lock_irqsave(&gm->lock, flags);
}
/* 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 */
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);
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);
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);
}
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);
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
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);
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);
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);
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);
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)
{
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);
}
/*
** 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
IRDA_DEBUG(0, __FUNCTION__ "(), failed Empty URB\n");
}
}
-#endif IU_BUG_KICK_TX
+#endif /* IU_BUG_KICK_TX */
/*------------------------------------------------------------------*/
/*
* 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? */
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);
break;
}
}
-#endif IU_BUG_KICK_TX
+#endif /* IU_BUG_KICK_TX */
/* Check speed URB */
purb = &(self->speed_urb);
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 */
printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
}
-#endif IU_DUMP_CLASS_DESC
+#endif /* IU_DUMP_CLASS_DESC */
/*------------------------------------------------------------------*/
/*
*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;
}
#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__)
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
# 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
+
--- /dev/null
+/*
+ * 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)
#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>
#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 {
/* 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
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");
#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
#define CMD_SETMODE 0x0009
#define CMD_ENABLEAUX 0x0111
#define CMD_SOFTRESET 0x0004
+#define CMD_LISTBSS 0x0103
/* Registers */
#define COMMAND 0x00
#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
* 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 {
#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 */
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 ----------*/
typedef struct {
u16 len;
char oui[3];
+ char zero;
u16 prodNum;
char manName[32];
char prodName[16];
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 */
} 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;
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));
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 );
struct airo_info *apriv = (struct airo_info *)dev->priv;
u16 savedInterrupts;
-
if (!netif_device_present(dev))
return;
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++;
}
}
* 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,
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 );
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,
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;
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",
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",
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",
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",
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",
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",
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;
}
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;
struct airo_info *apriv = (struct airo_info *)dev->priv;
CapabilityRid cap_rid;
StatusRid status_rid;
+ int i;
MOD_INC_USE_COUNT;
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"
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 );
}
"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,
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;
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;
{
stop_airo_card(pdev->driver_data, 1);
}
-
#endif
static int __init airo_init_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)
#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 */
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;
}
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;
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;
#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 */
#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) )
#endif /* ! HERMES_DEBUG */
-/*
- * Prototypes
- */
-
-static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0);
-
/*
* Internal functions
*/
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.. */
return -EBUSY;
/* Now we actually set up the transfer */
- retry:
hermes_write_reg(hw, sreg, id);
hermes_write_reg(hw, oreg, 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;
}
* 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)
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;
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
-/* orinoco.c 0.06f - (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.07 - (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
#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))
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
*/
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;
}
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) {
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 :
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)
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;
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);
(!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;
}
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;
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 */
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);
}
/*
hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
int err = 0;
- hermes_commsqual_t cq;
if (!priv->hw_ready)
return NULL;
}
#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);
#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;
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
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;
}
/* 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);
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;
}
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:
} 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)) {
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;
}
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;
extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv);
extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs);
-
#endif
-/* orinoco_cs.c 0.06f - (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.07 - (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/
#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' */
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);
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;
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) {
/**
* 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.
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
{ 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 },
"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);
}
* 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
* 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
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)
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");
#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"
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;
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,
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);
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);
++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;
}
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 *))
{
/*
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
#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 */
#define RISC_SYNC_VRO 0x0c
#define HWBASE_AD (448000)
-#define HWBASE_DA 31928 /* 48000 */
/* -------------------------------------------------------------- */
struct btaudio *next;
/* device info */
- int dsp_dev;
+ int dsp_digital;
+ int dsp_analog;
int mixer_dev;
struct pci_dev *pci;
unsigned int irq;
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;
/* -------------------------------------------------------------- */
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;
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 |
bta->read_count = 0;
bta->recording = 1;
if (debug)
- printk("btaudio: recording started\n");
+ printk(KERN_DEBUG "btaudio: recording started\n");
return 0;
}
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;
-}
/* -------------------------------------------------------------- */
if (NULL == bta)
return -ENODEV;
+ if (debug)
+ printk("btaudio: open mixer [%d]\n",minor);
file->private_data = bta;
return 0;
}
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;
}
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;
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,
/* -------------------------------------------------------------- */
-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;
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;
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)
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)
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) {
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;
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;
}
/* 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);
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:
}
}
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;
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,
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))
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;
}
}
if (count > 10) {
- printk("btaudio: Oops - irq mask cleared\n");
+ printk(KERN_WARNING
+ "btaudio: Oops - irq mask cleared\n");
btwrite(0, REG_INT_MASK);
}
}
bta->source = 1;
bta->bits = 8;
bta->channels = 1;
- if (analog) {
+ if (bta->analog) {
bta->decimation = 15;
} else {
bta->decimation = 0;
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",
/* 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;
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:
/* 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);
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);
}
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:
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),
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),
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),
{ 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 },
}
#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);
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;
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",
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;
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;
MODULE_AUTHOR("Brad Hards and another");
MODULE_DESCRIPTION("USB CDC Ethernet driver");
+MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE (usb, CDCEther_ids);
* - 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
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)
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;
}
usb_driver_release_interface(&scanner_driver,
&scn->scn_dev->actconfig->interface[scn->ifnum]);
+ devfs_unregister (scn->devfs);
+
kfree(scn->ibuf);
kfree(scn->obuf);
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 = {
*
* 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
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
// #define DEBUG
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");
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() */
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. */
/* 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.
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);
/*
- * $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
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) {
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)
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;
}
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))
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 }
};
{ 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 },
{ }
};
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;
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;
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:
}
#endif
}
+
+MODULE_LICENSE("GPL");
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)
{
*/
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);
}
/*
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);
#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
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)
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 */
(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
* <tomsoft@informatik.tu-chemnitz.de>
*/
+#include <linux/config.h>
+
#define TIMER_IRQ 0
/*
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 */
extern int mp_current_pci_id;
extern unsigned long mp_lapic_addr;
extern int pic_mode;
+extern int using_apic_timer;
#endif
* 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(); \
--- /dev/null
+#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 */
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
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC64 */
#define EM_SH 42 /* SuperH */
} 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;
#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
#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
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{
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{
} 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;
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
} 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 */
} 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 */
} 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
#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>
#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 */
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
#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 */
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
--- /dev/null
+/*
+ * 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
#define PCIPCI_TRITON 2
#define PCIPCI_NATOMA 4
#define PCIPCI_VIAETBF 8
+#define PCIPCI_VSFX 16
#endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */
#endif
#ifndef PREFETCH_STRIDE
-#define PREFETCH_STRIDE (4*L1_CACHE_BYTE)
+#define PREFETCH_STRIDE (4*L1_CACHE_BYTES)
#endif
#endif
#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
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 */
};
* 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>
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 */
* 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;
/* Go */
task->ptrace |= PT_PTRACED;
+ if (capable(CAP_SYS_PTRACE))
+ task->ptrace |= PT_PTRACE_CAP;
task_unlock(task);
write_lock_irq(&tasklist_lock);
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.
#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>
struct list_head *tmp;
int this_cpu, c;
+
spin_lock_prefetch(&runqueue_lock);
if (!current->active_mm) BUG();
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;
#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))
*/
int C_A_D = 1;
+int cad_pid = 1;
/*
if (C_A_D)
schedule_task(&cad_tq);
else
- kill_proc(1, SIGINT, 1);
+ kill_proc(cad_pid, SIGINT, 1);
}
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;
{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},
/*
* 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;
}
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);
}
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);
}
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
+#include <linux/compiler.h>
int nr_swap_pages;
int nr_active_pages;
local_pages = ¤t->local_pages;
- if (__freed) {
+ if (likely(__freed)) {
/* pick from the last inserted so we're lifo */
entry = local_pages->next;
do {
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)
zone->lock = SPIN_LOCK_UNLOCKED;
zone->zone_pgdat = pgdat;
zone->free_pages = 0;
+ zone->need_balance = 0;
if (!size)
continue;
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);
/* 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;
}
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/compiler.h>
#include <asm/uaccess.h>
/*
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);
}
\
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); \
/* 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);
/* 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);
del_page_from_active_list(page);
add_page_to_inactive_list(page);
}
+ ClearPageReferenced(page);
}
void deactivate_page(struct page * page)
del_page_from_inactive_list(page);
add_page_to_active_list(page);
}
+ SetPageReferenced(page);
}
void activate_page(struct page * page)
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/file.h>
+#include <linux/compiler.h>
#include <asm/pgalloc.h>
{
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
if (freeable)
deactivate_page(page);
page_cache_release(page);
- return freeable;
+ return freeable & right_classzone;
}
}
/* 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;
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;
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--;
/* 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;
}
* 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)) {
}
}
- 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);
}
/* point of no return */
- if (__builtin_expect(!PageSwapCache(page), 1))
+ if (likely(!PageSwapCache(page)))
__remove_inode_page(page);
else
__delete_from_swap_cache(page);
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;
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;
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);
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))
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);
--- /dev/null
+#!/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 ""
--- /dev/null
+if [ ! -f .version ]
+then
+ echo 1
+else
+ expr 0`cat .version` + 1
+fi