Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 16776 Details for
Bug 27558
2.4.22 patches
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
00_benh_20030827
00_benh_20030827 (text/plain), 606.00 KB, created by
David Holm (RETIRED)
on 2003-08-29 13:25:24 UTC
(
hide
)
Description:
00_benh_20030827
Filename:
MIME Type:
Creator:
David Holm (RETIRED)
Created:
2003-08-29 13:25:24 UTC
Size:
606.00 KB
patch
obsolete
>diff -Naur linux-2.4.22-ppc-dev.orig/CHANGES linux-2.4.22-ppc-dev/CHANGES >--- linux-2.4.22-ppc-dev.orig/CHANGES 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/CHANGES 2003-08-25 23:37:44.000000000 +0200 >@@ -0,0 +1,2 @@ >+2.4.22-ben1 : First release >+ >diff -Naur linux-2.4.22-ppc-dev.orig/Documentation/Configure.help linux-2.4.22-ppc-dev/Documentation/Configure.help >--- linux-2.4.22-ppc-dev.orig/Documentation/Configure.help 2003-08-27 15:17:42.000000000 +0200 >+++ linux-2.4.22-ppc-dev/Documentation/Configure.help 2003-08-25 23:37:54.000000000 +0200 >@@ -27170,6 +27170,29 @@ > > If unsure, say N. > >+CONFIG_CPU_FREQ >+ Clock scaling allows you to change the clock speed of CPUs on the >+ fly. This is a nice method to save battery power on notebooks, >+ because the lower the clock speed, the less power the CPU consumes. >+ >+ For more information, take a look at linux/Documentation/cpufreq or >+ at <http://www.brodo.de/cpufreq/> >+ >+ If in doubt, say N. >+ >+CONFIG_CPU_FREQ_24_API >+ This enables the /proc/sys/cpu/ sysctl interface for controlling >+ CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. Note >+ that some drivers do not support this interface or offer less >+ functionality. >+ >+ If you say N here, you'll be able to control CPUFreq using the >+ new /proc/cpufreq interface. >+ >+ For details, take a look at linux/Documentation/cpufreq. >+ >+ If in doubt, say N. >+ > NatSemi SCx200 support > CONFIG_SCx200 > This provides basic support for the National Semiconductor SCx200 >diff -Naur linux-2.4.22-ppc-dev.orig/Documentation/cpufreq linux-2.4.22-ppc-dev/Documentation/cpufreq >--- linux-2.4.22-ppc-dev.orig/Documentation/cpufreq 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/Documentation/cpufreq 2003-08-25 23:37:43.000000000 +0200 >@@ -0,0 +1,361 @@ >+ CPU frequency and voltage scaling code in the Linux(TM) kernel >+ >+ >+ L i n u x C P U F r e q >+ >+ >+ >+ >+ Dominik Brodowski <linux@brodo.de> >+ David Kimdon <dwhedon@debian.org> >+ >+ >+ >+ Clock scaling allows you to change the clock speed of the CPUs on the >+ fly. This is a nice method to save battery power, because the lower >+ the clock speed, the less power the CPU consumes. >+ >+ >+ >+Contents: >+--------- >+1. Supported architectures >+2. User interface >+2.1 /proc/cpufreq interface [2.6] >+2.2. /proc/sys/cpu/ interface [2.4] >+3. CPUFreq core and interfaces >+3.1 General information >+3.2 CPUFreq notifiers >+3.3 CPUFreq architecture drivers >+4. Mailing list and Links >+ >+ >+ >+1. Supported architectures >+========================== >+ >+ARM: >+ ARM Integrator, SA 1100, SA1110 >+-------------------------------- >+ This driver will be ported to new CPUFreq core soon, so >+ far it will not work. >+ >+ >+AMD Elan: >+ SC400, SC410 >+-------------------------------- >+ You need to specify the highest allowed CPU frequency as >+ a module parameter ("max_freq") or as boot parameter >+ ("elanfreq="). Else the available speed range will be >+ limited to the speed at which the CPU runs while this >+ module is loaded. >+ >+ >+VIA Cyrix Longhaul: >+ VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, >+ VIA Cyrix Ezra, VIA Cyrix Ezra-T >+-------------------------------- >+ If you do not want to scale the Front Side Bus or voltage, >+ pass the module parameter "dont_scale_fsb 1" or >+ "dont_scale_voltage 1". Additionally, it is advised that >+ you pass the current Front Side Bus speed (in MHz) to >+ this module as module parameter "current_fsb", e.g. >+ "current_fsb 133" for a Front Side Bus speed of 133 MHz. >+ >+ >+Intel SpeedStep: >+ certain mobile Intel Pentium III (Coppermine), and all mobile >+ Intel Pentium III-M (Tualatin) and mobile Intel Pentium 4 P4-Ms. >+-------------------------------- >+ Unfortunately only modern Intel ICH2-M and ICH3-M chipsets are >+ supported. >+ >+ >+P4 CPU Clock Modulation: >+ Intel Pentium 4 Xeon processors >+--------------------------------- >+ Note that you can only switch the speed of two logical CPUs at >+ once - but each phyiscal CPU may have different throttling levels. >+ >+ >+PowerNow! K6: >+ mobile AMD K6-2+ / mobile K6-3+: >+-------------------------------- >+ No known issues. >+ >+ >+Transmeta Crusoe Longrun: >+ Transmeta Crusoe processors: >+-------------------------------- >+ Does not work with the 2.4. /proc/sys/cpu/ interface. >+ >+ >+ >+2. User Interface >+================= >+ >+2.1 /proc/cpufreq interface [2.6] >+*********************************** >+ >+Starting in the patches for kernel 2.5.33, CPUFreq uses a "policy" >+interface /proc/cpufreq. >+ >+When you "cat" this file, you'll find something like: >+ >+-- >+ minimum CPU frequency - maximum CPU frequency - policy >+CPU 0 1200000 ( 75%) - 1600000 (100%) - performance >+-- >+ >+This means the current policy allows this CPU to be run anywhere >+between 1.2 GHz (the value is in kHz) and 1.6 GHz with an eye towards >+performance. >+ >+To change the policy, "echo" the desired new policy into >+/proc/cpufreq. Use one of the following formats: >+ >+cpu_nr:min_freq:max_freq:policy >+cpu_nr%min_freq%max_freq%policy >+min_freq:max_freq:policy >+min_freq%max_freq%policy >+ >+with cpu_nr being the CPU which shall be affected, min_freq and >+max_freq the lower and upper limit of the CPU core frequency in kHz, >+and policy either "performance" or "powersave". >+A few examples: >+ >+root@notebook:#echo -n "0:0:0:powersave" > /proc/cpufreq >+ sets the CPU #0 to the lowest supported frequency. >+ >+root@notebook:#echo -n "1%100%100%performance" > /proc/cpufreq >+ sets the CPU #1 to the highest supported frequency. >+ >+root@notebook:#echo -n "1000000:2000000:performance" > /proc/cpufreq >+ to set the frequency of all CPUs between 1 GHz and 2 GHz and to >+ the policy "performance". >+ >+Please note that the values you "echo" into /proc/cpufreq are >+validated first, and may be limited by hardware or thermal >+considerations. Because of this, a read from /proc/cpufreq might >+differ from what was written into it. >+ >+ >+When you read /proc/cpufreq for the first time after a CPUFreq driver >+has been initialized, you'll see the "default policy" for this >+driver. If this does not suit your needs, you can pass a boot >+parameter to the cpufreq core. Use the following syntax for this: >+ "cpufreq=min_freq:max_freq:policy", i.e. you may not chose a >+specific CPU and you need to specify the limits in kHz and not in >+per cent. >+ >+ >+2.2 /proc/cpufreq interface [2.4] >+*********************************** >+ >+Previsiously (and still available as a config option), CPUFreq used >+a "sysctl" interface which is located in >+ /proc/sys/cpu/0/ >+ /proc/sys/cpu/1/ ... (SMP only) >+ >+In these directories, you will find three files of importance for >+CPUFreq: speed-max, speed-min and speed: >+ >+speed shows the current CPU frequency in kHz, >+speed-min the minimum supported CPU frequency, and >+speed-max the maximum supported CPU frequency. >+ >+ >+To change the CPU frequency, "echo" the desired CPU frequency (in kHz) >+to speed. For example, to set the CPU speed to the lowest/highest >+allowed frequency do: >+ >+root@notebook:# cat /proc/sys/cpu/0/speed-min > /proc/sys/cpu/0/speed >+root@notebook:# cat /proc/sys/cpu/0/speed-max > /proc/sys/cpu/0/speed >+ >+ >+ >+3. CPUFreq core and interfaces >+=============================== >+ >+3.1 General information >+************************* >+ >+The CPUFreq core code is located in linux/kernel/cpufreq.c. This >+cpufreq code offers a standardized interface for the CPUFreq >+architecture drivers (those pieces of code that do actual >+frequency transitions), as well as to "notifiers". These are device >+drivers or other part of the kernel that need to be informed of >+policy changes (like thermal modules like ACPI) or of all >+frequency changes (like timing code) or even need to force certain >+speed limits (like LCD drivers on ARM architecture). Additionally, the >+kernel "constant" loops_per_jiffy is updated on frequency changes >+here. >+ >+ >+3.2 CPUFreq notifiers >+*********************** >+ >+CPUFreq notifiers conform to the standard kernel notifier interface. >+See linux/include/linux/notifier.h for details on notifiers. >+ >+There are two different CPUFreq notifiers - policy notifiers and >+transition notifiers. >+ >+ >+3.2.1 CPUFreq policy notifiers >+****************************** >+ >+These are notified when a new policy is intended to be set. Each >+CPUFreq policy notifier is called three times for a policy transition: >+ >+1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if >+ they see a need for this - may it be thermal considerations or >+ hardware limitations. >+ >+2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid >+ hardware failure. >+ >+3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy >+ - if two hardware drivers failed to agree on a new policy before this >+ stage, the incompatible hardware shall be shut down, and the user >+ informed of this. >+ >+The phase is specified in the second argument to the notifier. >+ >+The third argument, a void *pointer, points to a struct cpufreq_policy >+consisting of five values: cpu, min, max, policy and max_cpu_freq. Min >+and max are the lower and upper frequencies (in kHz) of the new >+policy, policy the new policy, cpu the number of the affected CPU or >+CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported >+CPU frequency. This value is given for informational purposes only. >+ >+ >+3.2.2 CPUFreq transition notifiers >+********************************** >+ >+These are notified twice when the CPUfreq driver switches the CPU core >+frequency and this change has any external implications. >+ >+The second argument specifies the phase - CPUFREQ_PRECHANGE or >+CPUFREQ_POSTCHANGE. >+ >+The third argument is a struct cpufreq_freqs with the following >+values: >+cpu - number of the affected CPU or CPUFREQ_ALL_CPUS >+old - old frequency >+new - new frequency >+ >+ >+3.3 CPUFreq architecture drivers >+********************************** >+ >+CPUFreq architecture drivers are the pieces of kernel code that >+actually perform CPU frequency transitions. These need to be >+initialized separately (separate initcalls), and may be >+modularized. They interact with the CPUFreq core in the following way: >+ >+cpufreq_register() >+------------------ >+cpufreq_register registers an arch driver to the CPUFreq core. Please >+note that only one arch driver may be registered at any time. -EBUSY >+is returned when an arch driver is already registered. The argument to >+cpufreq_register, struct cpufreq_driver *driver, is described later. >+ >+cpufreq_unregister() >+-------------------- >+cpufreq_unregister unregisters an arch driver, e.g. on module >+unloading. Please note that there is no check done that this is called >+from the driver which actually registered itself to the core, so >+please only call this function when you are sure the arch driver got >+registered correctly before. >+ >+cpufreq_notify_transition() >+--------------------------- >+On "dumb" hardware where only fixed frequency can be set, the driver >+must call cpufreq_notify_transition() once before, and once after the >+actual transition. >+ >+struct cpufreq_driver >+--------------------- >+On initialization, the arch driver is supposed to pass a pointer >+to a struct cpufreq_driver *cpufreq_driver consisting of the following >+entries: >+ >+cpufreq_verify_t verify: This is a pointer to a function with the >+ following definition: >+ void verify_function (struct cpufreq_policy *policy). >+ This function must verify the new policy is within the limits >+ supported by the CPU, and at least one supported CPU is within >+ this range. It may be useful to use cpufreq.h / >+ cpufreq_verify_within_limits for this. >+ >+cpufreq_setpolicy_t setpolicy: This is a pointer to a function with >+ the following definition: >+ void setpolicy_function (struct cpufreq_policy *policy). >+ This function must set the CPU to the new policy. If it is a >+ "dumb" CPU which only allows fixed frequencies to be set, it >+ shall set it to the lowest within the limit for >+ CPUFREQ_POLICY_POWERSAVE, and to the highest for >+ CPUFREQ_POLICY_PERFORMANCE. Once CONFIG_CPU_FREQ_DYNAMIC is >+ implemented, it can use a dynamic method to adjust the speed >+ between the lower and upper limit. >+ >+struct cpufreq_policy *policy: This is an array of NR_CPUS struct >+ cpufreq_policies, containing the current policies set for these >+ CPUs. Note that policy[0].max_cpu_freq must contain the >+ absolute maximum CPU frequency supported by _all_ CPUs. >+ >+In case the driver is expected to run with the 2.4.-style API >+(/proc/sys/cpu/.../), two more values must be passed >+#ifdef CONFIG_CPU_FREQ_24_API >+ unsigned int cpu_min_freq; >+ unsigned int cpu_cur_freq[NR_CPUS]; >+#endif >+ with cpu_min_freq being the minimum CPU frequency supported by >+ the CPUs; and the entries in cpu_cur_freq reflecting the >+ current speed of the appropriate CPU. >+ >+Some Requirements to CPUFreq architecture drivers >+------------------------------------------------- >+* Only call cpufreq_register() when the ability to switch CPU >+ frequencies is _verified_ or can't be missing >+* cpufreq_unregister() may only be called if cpufreq_register() has >+ been successfully(!) called before. >+* kfree() the struct cpufreq_driver only after the call to >+ cpufreq_unregister(), unless cpufreq_register() failed. >+* Be aware that there is currently no error management in the >+ setpolicy() code in the CPUFreq core. So only call yourself a >+ cpufreq_driver if you are really a working cpufreq_driver! >+ >+ >+ >+4. Mailing list and Links >+************************* >+ >+ >+Mailing List >+------------ >+There is a CPU frequency changing CVS commit and general list where >+you can report bugs, problems or submit patches. To post a message, >+send an email to cpufreq@www.linux.org.uk, to subscribe go to >+http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the >+mailing list are available to subscribers at >+http://www.linux.org.uk/mailman/private/cpufreq/. >+ >+ >+Links >+----- >+the FTP archives: >+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/ >+ >+how to access the CVS repository: >+* http://cvs.arm.linux.org.uk/ >+ >+the CPUFreq Mailing list: >+* http://www.linux.org.uk/mailman/listinfo/cpufreq >+ >+Clock and voltage scaling for the SA-1100: >+* http://www.lart.tudelft.nl/projects/scaling >+ >+CPUFreq project homepage >+* http://www.brodo.de/cpufreq/ >diff -Naur linux-2.4.22-ppc-dev.orig/Documentation/laptop-mode.sh linux-2.4.22-ppc-dev/Documentation/laptop-mode.sh >--- linux-2.4.22-ppc-dev.orig/Documentation/laptop-mode.sh 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/Documentation/laptop-mode.sh 2003-08-25 23:37:28.000000000 +0200 >@@ -0,0 +1,42 @@ >+#!/bin/sh >+# >+# start of stop laptop mode, best run by a power management daemon when >+# ac gets connected/disconnected from a laptop >+# >+# FIXME: assumes HZ == 100 >+ >+# age time, in seconds. should be put into a sysconfig file >+MAX_AGE=600 >+ >+# kernel default dirty buffer age >+DEF_AGE=30 >+DEF_UPDATE=5 >+ >+if [ ! -w /proc/sys/vm/laptop_mode ]; then >+ echo "Kernel is not patched with laptop_mode patch" >+ exit 1 >+fi >+ >+case "$1" in >+ start) >+ AGE=$((100*$MAX_AGE)) >+ echo -n "Starting laptop mode" >+ echo "1" > /proc/sys/vm/laptop_mode >+ echo "30 500 0 0 $AGE $AGE 60 20 0" > /proc/sys/vm/bdflush >+ echo "." >+ ;; >+ stop) >+ U_AGE=$((100*$DEF_UPDATE)) >+ B_AGE=$((100*$DEF_AGE)) >+ echo -n "Stopping laptop mode" >+ echo "0" > /proc/sys/vm/laptop_mode >+ echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush >+ echo "." >+ ;; >+ *) >+ echo "$0 {start|stop}" >+ ;; >+ >+esac >+ >+exit 0 >diff -Naur linux-2.4.22-ppc-dev.orig/Documentation/laptop-mode.txt linux-2.4.22-ppc-dev/Documentation/laptop-mode.txt >--- linux-2.4.22-ppc-dev.orig/Documentation/laptop-mode.txt 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/Documentation/laptop-mode.txt 2003-08-25 23:37:29.000000000 +0200 >@@ -0,0 +1,72 @@ >+Laptop mode >+=========== >+ >+This small doc describes the 2.4 laptop mode patch. >+ >+Last updated 2003-05-25, Jens Axboe <axboe@suse.de> >+ >+Introduction >+------------ >+ >+A few properties of the Linux vm makes it virtually impossible to attempt >+to spin down the hard drive in a laptop for a longer period of time (more >+than a handful of seconds). This means you are lucky if you can even reach >+the break even point with regards to power consumption, let alone expect any >+decrease. >+ >+One problem is the age time of dirty buffers. Linux uses 30 seconds per >+default, so if you dirty any data then flusing of that data will commence >+at most 30 seconds from then. Another is the journal commit interval of >+journalled file systems such as ext3, which is 5 seconds on a stock kernel. >+Both of these are tweakable either from proc/sysctl or as mount options >+though, and thus partly solvable from user space. >+ >+The kernel update daemon (kupdated) also runs at specific intervals, flushing >+old dirty data out. Default is every 5 seconds, this too can be tweaked >+from sysctl. >+ >+So what does the laptop mode patch do? It attempts to fully utilize the >+hard drive once it has been spun up, flushing the old dirty data out to >+disk. Instead of flushing just the expired data, it will clean everything. >+When a read causes the disk to spin up, we kick off this flushing after >+a few seconds. This means that once the disk spins down again, everything >+is up to date. That allows longer dirty data and journal expire times. >+ >+It follows that you have to set long expire times to get long spin downs. >+This means you could potentially loose 10 minutes worth of data, if you >+set a 10 minute expire count instead of just 30 seconds worth. The biggest >+risk here is undoubtedly running out of battery. >+ >+Settings >+-------- >+ >+The main knob is /proc/sys/vm/laptop mode. Setting that to 1 switches the >+vm (and block layer) to laptop mode. Leaving it to 0 makes the kernel work >+like before. When in laptop mode, you also want to extend the intervals >+desribed above. See the laptop-mode.sh script for how to do that. >+ >+It can happen that the disk still keeps spinning up and you don't quite >+know why or what causes it. The laptop mode patch has a little helper for >+that as well, /proc/sys/vm/block-dump. When set to 1, it will dump info to >+the kernel message buffer about what process caused the io. Be very careful >+when playing with this setting, it is advisable to shut down syslog first! >+ >+Result >+------ >+ >+Using the laptop-mode.sh script with its default settings, I get the full >+10 minutes worth of drive spin down. Provided your work load is cached, >+the disk will only spin up every 10 minutes (well actually, 9 minutes and 55 >+seconds due to the 5 second delay in flushing dirty data after the last read >+completes). I can't tell you exactly how much extra battery life you will >+gain in laptop mode, it will vary greatly on the laptop and workload in >+question. The only way to know for sure is to try it out. Getting 10% extra >+battery life is not unrealistic. >+ >+Notes >+----- >+ >+Patch only changes journal expire time for ext3. reiserfs uses a hardwire >+value, should be trivial to adapt though (basically just make it call >+get_buffer_flushtime() and uses that). I have not looked at other >+journalling file systems, I'll happily accept patches to rectify that! >diff -Naur linux-2.4.22-ppc-dev.orig/MAINTAINERS linux-2.4.22-ppc-dev/MAINTAINERS >--- linux-2.4.22-ppc-dev.orig/MAINTAINERS 2003-08-27 15:17:43.000000000 +0200 >+++ linux-2.4.22-ppc-dev/MAINTAINERS 2003-08-25 23:37:31.000000000 +0200 >@@ -759,6 +759,12 @@ > L: linux-kernel@vger.kernel.org > S: Maintained > >+HFSPLUS FILESYSTEM >+P: Brad Boyer >+M: flar@allandria.com >+W: http://sourceforge.net/projects/linux-hfsplus/ >+S: Maintained >+ > HGA FRAMEBUFFER DRIVER > P: Ferenc Bakonyi > M: fero@drama.obuda.kando.hu >@@ -1309,7 +1315,7 @@ > NVIDIA (RIVA) FRAMEBUFFER DRIVER > P: Ani Joshi > M: ajoshi@kernel.crashing.org >-L: linux-nvidia@lists.surfsouth.com >+L: linux-fbdev-devel@lists.sourceforge.net > S: Maintained > > OLYMPIC NETWORK DRIVER >diff -Naur linux-2.4.22-ppc-dev.orig/Makefile linux-2.4.22-ppc-dev/Makefile >--- linux-2.4.22-ppc-dev.orig/Makefile 2003-08-27 15:17:43.000000000 +0200 >+++ linux-2.4.22-ppc-dev/Makefile 2003-08-25 23:37:55.000000000 +0200 >@@ -1,7 +1,7 @@ > VERSION = 2 > PATCHLEVEL = 4 > SUBLEVEL = 22 >-EXTRAVERSION = >+EXTRAVERSION = -ben1 > > KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) > >diff -Naur linux-2.4.22-ppc-dev.orig/README.BENH linux-2.4.22-ppc-dev/README.BENH >--- linux-2.4.22-ppc-dev.orig/README.BENH 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/README.BENH 2003-08-25 23:37:30.000000000 +0200 >@@ -0,0 +1,23 @@ >+Welcome to my PowerMac tree. >+ >+In addition to the standard feature set of kernel.org's 2.4.22, this >+tree includes small fixes that didn't make it into 2.4.21, including all >+of what was present as of 2.4.21-ben3. Some of the major additions are: >+ >+ - Laptop mode patch (Jens Axboe). See Documentation/laptop_mode.sh script >+ - Andrea Arcangeli's silent-stack-overflow patch >+ - CPU Frequency switching support on some laptops >+ - Support for UniNorth AGP in the agpgart driver (though it's strongly >+ recommended that you use Michel's Danzer DRM module for that to work >+ properly) >+ - Support for blinking the laptop LED on internal HD activity >+ (Jens and me) >+ - Improved support for lba48 capable disks (Jens Axboe) >+ - Updated rivafb with support for more cards & eMac >+ - Updated sungem driver, supports more chips & recent PHYs >+ - Updated dmasound driver to support tumbler & snapper >+ - Add reporting of OF device path of IDE interfaces in /proc/ide >+ - Fixes for CompactFlash cards >+ - Fixes to vmlinux.coff oldworld wrapper >+ - Better TB sync code for 2 CPU machines from Samuel Rydth >+ >diff -Naur linux-2.4.22-ppc-dev.orig/arch/alpha/mm/fault.c linux-2.4.22-ppc-dev/arch/alpha/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/alpha/mm/fault.c 2002-11-29 00:53:08.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/alpha/mm/fault.c 2003-08-25 23:37:28.000000000 +0200 >@@ -124,7 +124,7 @@ > goto good_area; > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/arm/mm/fault-common.c linux-2.4.22-ppc-dev/arch/arm/mm/fault-common.c >--- linux-2.4.22-ppc-dev.orig/arch/arm/mm/fault-common.c 2003-08-27 15:17:43.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/arm/mm/fault-common.c 2003-08-25 23:38:04.000000000 +0200 >@@ -254,7 +254,7 @@ > goto survive; > > check_stack: >- if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) >+ if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr, NULL)) > goto good_area; > out: > return fault; >diff -Naur linux-2.4.22-ppc-dev.orig/arch/cris/mm/fault.c linux-2.4.22-ppc-dev/arch/cris/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/cris/mm/fault.c 2003-08-27 15:17:43.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/cris/mm/fault.c 2003-08-25 23:37:53.000000000 +0200 >@@ -323,7 +323,7 @@ > if (address + PAGE_SIZE < rdusp()) > goto bad_area; > } >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > > /* >diff -Naur linux-2.4.22-ppc-dev.orig/arch/i386/mm/fault.c linux-2.4.22-ppc-dev/arch/i386/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/i386/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/i386/mm/fault.c 2003-08-25 23:37:48.000000000 +0200 >@@ -32,7 +32,7 @@ > */ > int __verify_write(const void * addr, unsigned long size) > { >- struct vm_area_struct * vma; >+ struct vm_area_struct * vma, * prev_vma; > unsigned long start = (unsigned long) addr; > > if (!size) >@@ -78,7 +78,8 @@ > check_stack: > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, start) == 0) >+ find_vma_prev(current->mm, start, &prev_vma); >+ if (expand_stack(vma, start, prev_vma) == 0) > goto good_area; > > bad_area: >@@ -141,7 +142,7 @@ > { > struct task_struct *tsk; > struct mm_struct *mm; >- struct vm_area_struct * vma; >+ struct vm_area_struct * vma, * prev_vma; > unsigned long address; > unsigned long page; > unsigned long fixup; >@@ -202,7 +203,8 @@ > if (address + 32 < regs->esp) > goto bad_area; > } >- if (expand_stack(vma, address)) >+ find_vma_prev(mm, address, &prev_vma); >+ if (expand_stack(vma, address, prev_vma)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ia64/mm/fault.c linux-2.4.22-ppc-dev/arch/ia64/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/ia64/mm/fault.c 2003-08-27 15:17:44.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ia64/mm/fault.c 2003-08-25 23:37:28.000000000 +0200 >@@ -159,7 +159,7 @@ > if (rgn_index(address) != rgn_index(vma->vm_start) > || rgn_offset(address) >= RGN_MAP_LIMIT) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > } else { > vma = prev_vma; >diff -Naur linux-2.4.22-ppc-dev.orig/arch/m68k/mm/fault.c linux-2.4.22-ppc-dev/arch/m68k/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/m68k/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/m68k/mm/fault.c 2003-08-25 23:37:46.000000000 +0200 >@@ -120,7 +120,7 @@ > if (address + 256 < rdusp()) > goto map_err; > } >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto map_err; > > /* >diff -Naur linux-2.4.22-ppc-dev.orig/arch/mips/mm/fault.c linux-2.4.22-ppc-dev/arch/mips/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/mips/mm/fault.c 2003-08-27 15:17:46.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/mips/mm/fault.c 2003-08-25 23:37:48.000000000 +0200 >@@ -114,7 +114,7 @@ > goto good_area; > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/mips64/mm/fault.c linux-2.4.22-ppc-dev/arch/mips64/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/mips64/mm/fault.c 2003-08-27 15:17:46.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/mips64/mm/fault.c 2003-08-25 23:38:01.000000000 +0200 >@@ -137,7 +137,7 @@ > goto good_area; > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/boot/pmac/coffmain.c linux-2.4.22-ppc-dev/arch/ppc/boot/pmac/coffmain.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/boot/pmac/coffmain.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/boot/pmac/coffmain.c 2003-08-25 23:37:53.000000000 +0200 >@@ -18,6 +18,7 @@ > extern char _start, _end; > > extern char *claim(unsigned, unsigned, unsigned); >+extern int map(unsigned, unsigned, unsigned); > extern char image_data[], initrd_data[]; > extern int initrd_len, image_len; > extern int getprop(void *, const char *, void *, int); >@@ -34,16 +35,19 @@ > char *begin_avail, *end_avail; > char *avail_high; > >-#define RAM_START 0 >-#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */ >- >-#define PROG_START RAM_START >-#define PROG_SIZE 0x00400000 >- > #define SCRATCH_SIZE (128 << 10) > > static char heap[SCRATCH_SIZE]; > >+//static unsigned long ram_start = 0; >+//static unsigned long ram_end = 0x800000; >+//static unsigned long prog_start = 0; >+//static unsigned long prog_size = 0x380000; >+ >+static unsigned long ram_start = 0; >+static unsigned long ram_end = 0x1000000; >+static unsigned long prog_start = 0x800000; >+static unsigned long prog_size = 0x800000; > typedef void (*kernel_start_t)(int, int, void *); > > void boot(int a1, int a2, void *prom) >@@ -54,32 +58,34 @@ > unsigned initrd_start, initrd_size; > > printf("coffboot starting: loaded at 0x%p\n", &_start); >- setup_bats(RAM_START); >+ setup_bats(ram_start); > > initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); > if (initrd_size) { >- initrd_start = (RAM_END - initrd_size) & ~0xFFF; >+ initrd_start = (ram_end - initrd_size) & ~0xFFF; > a1 = initrd_start; > a2 = initrd_size; >- claim(initrd_start, RAM_END - initrd_start, 0); >+ claim(initrd_start, ram_end - initrd_start, 0); > printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", > initrd_start, (char *)(&__ramdisk_begin), initrd_size); > memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); >+ prog_size = initrd_start - prog_start; > } else > a2 = 0xdeadbeef; > > im = (char *)(&__image_begin); > len = (char *)(&__image_end) - (char *)(&__image_begin); > /* claim 4MB starting at 0 */ >- claim(0, PROG_SIZE, 0); >- dst = (void *) RAM_START; >+ claim(prog_start, prog_size, 0); >+ map(prog_start, prog_start, prog_size); >+ dst = (void *) prog_start; > if (im[0] == 0x1f && im[1] == 0x8b) { > /* set up scratch space */ > begin_avail = avail_high = avail_ram = heap; > end_avail = heap + sizeof(heap); > printf("heap at 0x%p\n", avail_ram); > printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); >- gunzip(dst, PROG_SIZE, im, &len); >+ gunzip(dst, prog_size, im, &len); > printf("done %u bytes\n", len); > printf("%u bytes of heap consumed, max in use %u\n", > avail_high - begin_avail, heap_max); >@@ -89,9 +95,9 @@ > > flush_cache(dst, len); > make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac, >- (PROG_START + PROG_SIZE)); >+ (prog_start + prog_size)); > >- sa = (unsigned long)PROG_START; >+ sa = (unsigned long)prog_start; > printf("start address = 0x%x\n", sa); > > (*(kernel_start_t)sa)(a1, a2, prom); >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/boot/pmac/misc.S linux-2.4.22-ppc-dev/arch/ppc/boot/pmac/misc.S >--- linux-2.4.22-ppc-dev.orig/arch/ppc/boot/pmac/misc.S 2003-06-13 16:51:31.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/boot/pmac/misc.S 2003-08-25 23:37:30.000000000 +0200 >@@ -9,7 +9,7 @@ > .text > > /* >- * Use the BAT3 registers to map the 1st 8MB of RAM to >+ * Use the BAT2 & 3 registers to map the 1st 16MB of RAM to > * the address given as the 1st argument. > */ > .globl setup_bats >@@ -22,6 +22,10 @@ > mtibatl 3,0 /* invalidate BAT first */ > ori 3,3,4 /* set up BAT registers for 601 */ > li 4,0x7f >+ mtibatu 2,3 >+ mtibatl 2,4 >+ oris 3,3,0x80 >+ oris 4,4,0x80 > mtibatu 3,3 > mtibatl 3,4 > b 5f >@@ -29,6 +33,12 @@ > mtibatu 3,0 > ori 3,3,0xff /* set up BAT registers for 604 */ > li 4,2 >+ mtdbatl 2,4 >+ mtdbatu 2,3 >+ mtibatl 2,4 >+ mtibatu 2,3 >+ oris 3,3,0x80 >+ oris 4,4,0x80 > mtdbatl 3,4 > mtdbatu 3,3 > mtibatl 3,4 >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/boot/pmac/start.c linux-2.4.22-ppc-dev/arch/ppc/boot/pmac/start.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/boot/pmac/start.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/boot/pmac/start.c 2003-08-25 23:37:47.000000000 +0200 >@@ -11,12 +11,13 @@ > extern int strlen(const char *s); > extern void boot(int a1, int a2, void *prom); > >-int (*prom)(void *args); >+int (*prom)(void *); > > void *chosen_handle; > void *stdin; > void *stdout; > void *stderr; >+void *prom_mmu; > > void exit(void); > void *finddevice(const char *name); >@@ -35,6 +36,8 @@ > stderr = stdout; > if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) > exit(); >+ if (getprop(chosen_handle, "mmu", &prom_mmu, sizeof(prom_mmu)) != 4) >+ exit(); > > boot(a1, a2, promptr); > for (;;) >@@ -195,6 +198,41 @@ > } > > int >+map(unsigned int phys, unsigned int virt, unsigned int size) >+{ >+ struct prom_args { >+ char *service; >+ int nargs; >+ int nret; >+ char *method; >+ void *mmu_ihandle; >+ int misc; >+ unsigned int phys; >+ unsigned int virt; >+ unsigned int size; >+ int ret0; >+ int ret1; >+ } args; >+ >+ if (prom_mmu == 0) { >+ printk("map() called, no MMU found\n"); >+ return -1; >+ } >+ args.service = "call-method"; >+ args.nargs = 6; >+ args.nret = 2; >+ args.method = "map"; >+ args.mmu_ihandle = prom_mmu; >+ args.misc = -1; >+ args.phys = phys; >+ args.virt = virt; >+ args.size = size; >+ (*prom)(&args); >+ >+ return (int)args.ret0; >+} >+ >+int > getprop(void *phandle, const char *name, void *buf, int buflen) > { > struct prom_args { >@@ -330,7 +368,7 @@ > } > > int >-printf(char *fmt, ...) >+printf(const char *fmt, ...) > { > va_list args; > int n; >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/config.in linux-2.4.22-ppc-dev/arch/ppc/config.in >--- linux-2.4.22-ppc-dev.orig/arch/ppc/config.in 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/config.in 2003-08-25 23:37:27.000000000 +0200 >@@ -53,6 +53,17 @@ > define_bool CONFIG_PPC_STD_MMU y > fi > >+bool 'CPU Frequency scaling' CONFIG_CPU_FREQ >+if [ "$CONFIG_CPU_FREQ" = "y" ]; then >+ bool ' /proc/sys/cpu/ interface (2.4.)' CONFIG_CPU_FREQ_24_API >+ if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then >+ define_bool CONFIG_CPU_FREQ_26_API y >+ fi >+ if [ "$CONFIG_ADB_PMU" = "y" ]; then >+ bool " Support for Apple PowerBooks" CONFIG_CPU_FREQ_PMAC >+ fi >+fi >+ > if [ "$CONFIG_8260" = "y" ]; then > define_bool CONFIG_SERIAL_CONSOLE y > bool 'Support for EST8260' CONFIG_EST8260 >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/configs/briq_defconfig linux-2.4.22-ppc-dev/arch/ppc/configs/briq_defconfig >--- linux-2.4.22-ppc-dev.orig/arch/ppc/configs/briq_defconfig 2003-06-13 16:51:31.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/configs/briq_defconfig 2003-08-25 23:37:42.000000000 +0200 >@@ -1,5 +1,5 @@ > # >-# Automatically generated make config: don't edit >+# Automatically generated by make menuconfig: don't edit > # > # CONFIG_UID16 is not set > # CONFIG_RWSEM_GENERIC_SPINLOCK is not set >@@ -30,6 +30,7 @@ > # CONFIG_8xx is not set > # CONFIG_8260 is not set > CONFIG_PPC_STD_MMU=y >+# CONFIG_CPU_FREQ is not set > CONFIG_ALL_PPC=y > # CONFIG_APUS is not set > # CONFIG_SPRUCE is not set >@@ -191,10 +192,6 @@ > # CONFIG_KHTTPD is not set > # CONFIG_ATM is not set > # CONFIG_VLAN_8021Q is not set >- >-# >-# >-# > # CONFIG_IPX is not set > CONFIG_ATALK=m > >@@ -232,10 +229,6 @@ > # IDE, ATA and ATAPI Block devices > # > CONFIG_BLK_DEV_IDE=y >- >-# >-# Please see Documentation/ide.txt for help/info on IDE drives >-# > # CONFIG_BLK_DEV_HD_IDE is not set > # CONFIG_BLK_DEV_HD is not set > CONFIG_BLK_DEV_IDEDISK=y >@@ -247,10 +240,6 @@ > CONFIG_BLK_DEV_IDEFLOPPY=y > CONFIG_BLK_DEV_IDESCSI=y > # CONFIG_IDE_TASK_IOCTL is not set >- >-# >-# IDE chipset support/bugfixes >-# > # CONFIG_BLK_DEV_CMD640 is not set > # CONFIG_BLK_DEV_CMD640_ENHANCED is not set > # CONFIG_BLK_DEV_ISAPNP is not set >@@ -588,14 +577,6 @@ > # Joysticks > # > # CONFIG_INPUT_GAMEPORT is not set >- >-# >-# Input core support is needed for gameports >-# >- >-# >-# Input core support is needed for joysticks >-# > # CONFIG_QIC02_TAPE is not set > # CONFIG_IPMI_HANDLER is not set > # CONFIG_IPMI_PANIC_EVENT is not set >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/configs/pmac_defconfig linux-2.4.22-ppc-dev/arch/ppc/configs/pmac_defconfig >--- linux-2.4.22-ppc-dev.orig/arch/ppc/configs/pmac_defconfig 2003-06-13 16:51:31.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/configs/pmac_defconfig 2003-08-25 23:37:27.000000000 +0200 >@@ -30,6 +30,10 @@ > # CONFIG_8xx is not set > # CONFIG_8260 is not set > CONFIG_PPC_STD_MMU=y >+CONFIG_CPU_FREQ=y >+# CONFIG_CPU_FREQ_24_API is not set >+CONFIG_CPU_FREQ_26_API=y >+CONFIG_CPU_FREQ_PMAC=y > CONFIG_ALL_PPC=y > # CONFIG_APUS is not set > # CONFIG_SPRUCE is not set >@@ -38,15 +42,13 @@ > # CONFIG_GEMINI is not set > # CONFIG_SMP is not set > CONFIG_ALTIVEC=y >-CONFIG_TAU=y >-# CONFIG_TAU_INT is not set >-# CONFIG_TAU_AVERAGE is not set >+# CONFIG_TAU is not set > CONFIG_PPC_ISATIMER=y > > # > # General setup > # >-# CONFIG_HIGHMEM is not set >+CONFIG_HIGHMEM=y > # CONFIG_ISA is not set > # CONFIG_EISA is not set > # CONFIG_SBUS is not set >@@ -76,10 +78,11 @@ > # Parallel port support > # > # CONFIG_PARPORT is not set >-CONFIG_GEN_RTC=y >+# CONFIG_GEN_RTC is not set >+CONFIG_PPC_RTC=y > CONFIG_PPC601_SYNC_FIX=y > CONFIG_PROC_DEVICETREE=y >-CONFIG_PPC_RTAS=y >+# CONFIG_PPC_RTAS is not set > # CONFIG_PREP_RESIDUAL is not set > # CONFIG_PROC_PREPRESIDUAL is not set > CONFIG_PPCBUG_NVRAM=y >@@ -99,7 +102,7 @@ > # > # Block devices > # >-CONFIG_BLK_DEV_FD=m >+# CONFIG_BLK_DEV_FD is not set > # CONFIG_BLK_DEV_XD is not set > # CONFIG_PARIDE is not set > # CONFIG_BLK_CPQ_DA is not set >@@ -152,10 +155,10 @@ > # > CONFIG_IP_NF_CONNTRACK=m > CONFIG_IP_NF_FTP=m >-CONFIG_IP_NF_AMANDA=m >-CONFIG_IP_NF_TFTP=m >+# CONFIG_IP_NF_AMANDA is not set >+# CONFIG_IP_NF_TFTP is not set > CONFIG_IP_NF_IRC=m >-# CONFIG_IP_NF_QUEUE is not set >+CONFIG_IP_NF_QUEUE=m > CONFIG_IP_NF_IPTABLES=m > CONFIG_IP_NF_MATCH_LIMIT=m > CONFIG_IP_NF_MATCH_MAC=m >@@ -181,14 +184,16 @@ > CONFIG_IP_NF_NAT_NEEDED=y > CONFIG_IP_NF_TARGET_MASQUERADE=m > CONFIG_IP_NF_TARGET_REDIRECT=m >-CONFIG_IP_NF_NAT_AMANDA=m > # CONFIG_IP_NF_NAT_LOCAL is not set > CONFIG_IP_NF_NAT_SNMP_BASIC=m > CONFIG_IP_NF_NAT_IRC=m > CONFIG_IP_NF_NAT_FTP=m >-CONFIG_IP_NF_NAT_TFTP=m >-# CONFIG_IP_NF_MANGLE is not set >-# CONFIG_IP_NF_TARGET_LOG is not set >+CONFIG_IP_NF_MANGLE=m >+CONFIG_IP_NF_TARGET_TOS=m >+CONFIG_IP_NF_TARGET_ECN=m >+CONFIG_IP_NF_TARGET_DSCP=m >+CONFIG_IP_NF_TARGET_MARK=m >+CONFIG_IP_NF_TARGET_LOG=m > CONFIG_IP_NF_TARGET_ULOG=m > CONFIG_IP_NF_TARGET_TCPMSS=m > CONFIG_IP_NF_ARPTABLES=m >@@ -198,7 +203,13 @@ > # CONFIG_IP_NF_COMPAT_IPFWADM is not set > # CONFIG_IPV6 is not set > # CONFIG_KHTTPD is not set >-# CONFIG_ATM is not set >+CONFIG_ATM=y >+CONFIG_ATM_CLIP=y >+CONFIG_ATM_CLIP_NO_ICMP=y >+CONFIG_ATM_LANE=m >+CONFIG_ATM_MPOA=m >+CONFIG_ATM_BR2684=m >+# CONFIG_ATM_BR2684_IPFILTER is not set > # CONFIG_VLAN_8021Q is not set > > # >@@ -255,7 +266,7 @@ > # CONFIG_BLK_DEV_IDETAPE is not set > CONFIG_BLK_DEV_IDEFLOPPY=y > CONFIG_BLK_DEV_IDESCSI=y >-# CONFIG_IDE_TASK_IOCTL is not set >+CONFIG_IDE_TASK_IOCTL=y > > # > # IDE chipset support/bugfixes >@@ -272,9 +283,9 @@ > CONFIG_IDEDMA_PCI_AUTO=y > # CONFIG_IDEDMA_ONLYDISK is not set > CONFIG_BLK_DEV_IDEDMA=y >-# CONFIG_IDEDMA_PCI_WIP is not set >+CONFIG_IDEDMA_PCI_WIP=y > # CONFIG_BLK_DEV_ADMA100 is not set >-# CONFIG_BLK_DEV_AEC62XX is not set >+CONFIG_BLK_DEV_AEC62XX=y > # CONFIG_BLK_DEV_ALI15X3 is not set > # CONFIG_WDC_ALI15X3 is not set > # CONFIG_BLK_DEV_AMD74XX is not set >@@ -289,10 +300,10 @@ > # CONFIG_BLK_DEV_PIIX is not set > # CONFIG_BLK_DEV_NS87415 is not set > # CONFIG_BLK_DEV_OPTI621 is not set >-# CONFIG_BLK_DEV_PDC202XX_OLD is not set >-# CONFIG_PDC202XX_BURST is not set >-CONFIG_BLK_DEV_PDC202XX_NEW=m >-# CONFIG_PDC202XX_FORCE is not set >+CONFIG_BLK_DEV_PDC202XX_OLD=y >+CONFIG_PDC202XX_BURST=y >+CONFIG_BLK_DEV_PDC202XX_NEW=y >+CONFIG_PDC202XX_FORCE=y > # CONFIG_BLK_DEV_RZ1000 is not set > # CONFIG_BLK_DEV_SC1200 is not set > # CONFIG_BLK_DEV_SVWKS is not set >@@ -303,8 +314,10 @@ > # CONFIG_BLK_DEV_VIA82CXXX is not set > CONFIG_BLK_DEV_SL82C105=y > CONFIG_BLK_DEV_IDE_PMAC=y >+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y > CONFIG_BLK_DEV_IDEDMA_PMAC=y > CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y >+CONFIG_PMU_HD_BLINK=y > CONFIG_BLK_DEV_IDEDMA=y > CONFIG_BLK_DEV_IDEPCI=y > # CONFIG_IDE_CHIPSETS is not set >@@ -353,19 +366,12 @@ > # CONFIG_SCSI_AHA1542 is not set > # CONFIG_SCSI_AHA1740 is not set > # CONFIG_SCSI_AACRAID is not set >-CONFIG_SCSI_AIC7XXX=m >+CONFIG_SCSI_AIC7XXX=y > CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 > CONFIG_AIC7XXX_RESET_DELAY_MS=15000 > # CONFIG_AIC7XXX_PROBE_EISA_VL is not set > # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set >-# CONFIG_AIC7XXX_DEBUG_ENABLE is not set >-CONFIG_AIC7XXX_DEBUG_MASK=0 >-# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set > # CONFIG_SCSI_AIC79XX is not set >-CONFIG_SCSI_AIC7XXX_OLD=m >-# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set >-CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 >-CONFIG_AIC7XXX_OLD_PROC_STATS=y > # CONFIG_SCSI_DPT_I2O is not set > CONFIG_SCSI_ADVANSYS=m > # CONFIG_SCSI_IN2000 is not set >@@ -407,7 +413,7 @@ > # CONFIG_SCSI_DEBUG is not set > CONFIG_SCSI_MESH=y > CONFIG_SCSI_MESH_SYNC_RATE=5 >-CONFIG_SCSI_MESH_RESET_DELAY_MS=500 >+CONFIG_SCSI_MESH_RESET_DELAY_MS=4000 > CONFIG_SCSI_MAC53C94=y > > # >@@ -436,10 +442,11 @@ > CONFIG_IEEE1394_SBP2=m > # CONFIG_IEEE1394_SBP2_PHYS_DMA is not set > CONFIG_IEEE1394_ETH1394=m >-# CONFIG_IEEE1394_DV1394 is not set >+CONFIG_IEEE1394_DV1394=m > CONFIG_IEEE1394_RAWIO=m > # CONFIG_IEEE1394_CMP is not set > # CONFIG_IEEE1394_VERBOSEDEBUG is not set >+CONFIG_IEEE1394_OUI_DB=y > > # > # Network device support >@@ -453,7 +460,7 @@ > # CONFIG_DUMMY is not set > # CONFIG_BONDING is not set > # CONFIG_EQUALIZER is not set >-# CONFIG_TUN is not set >+CONFIG_TUN=m > # CONFIG_ETHERTAP is not set > > # >@@ -537,6 +544,7 @@ > CONFIG_PPP_DEFLATE=y > CONFIG_PPP_BSDCOMP=m > # CONFIG_PPPOE is not set >+# CONFIG_PPPOATM is not set > # CONFIG_SLIP is not set > > # >@@ -554,6 +562,7 @@ > CONFIG_APPLE_AIRPORT=m > # CONFIG_PLX_HERMES is not set > CONFIG_PCI_HERMES=m >+# CONFIG_TMD_HERMES is not set > > # > # Wireless Pcmcia cards support >@@ -598,6 +607,21 @@ > # CONFIG_AIRONET4500_CS is not set > > # >+# ATM drivers >+# >+# CONFIG_ATM_TCP is not set >+# CONFIG_ATM_LANAI is not set >+# CONFIG_ATM_ENI is not set >+# CONFIG_ATM_FIRESTREAM is not set >+# CONFIG_ATM_ZATM is not set >+# CONFIG_ATM_NICSTAR is not set >+# CONFIG_ATM_IDT77252 is not set >+# CONFIG_ATM_AMBASSADOR is not set >+# CONFIG_ATM_HORIZON is not set >+# CONFIG_ATM_IA is not set >+# CONFIG_ATM_FORE200E_MAYBE is not set >+ >+# > # Amateur Radio support > # > # CONFIG_HAMRADIO is not set >@@ -613,7 +637,7 @@ > CONFIG_IRLAN=m > CONFIG_IRNET=m > CONFIG_IRCOMM=m >-# CONFIG_IRDA_ULTRA is not set >+CONFIG_IRDA_ULTRA=y > > # > # IrDA options >@@ -630,7 +654,7 @@ > # SIR device drivers > # > CONFIG_IRTTY_SIR=m >-# CONFIG_IRPORT_SIR is not set >+CONFIG_IRPORT_SIR=m > > # > # Dongle support >@@ -652,7 +676,78 @@ > # > # ISDN subsystem > # >-# CONFIG_ISDN is not set >+CONFIG_ISDN=m >+CONFIG_ISDN_BOOL=y >+CONFIG_ISDN_PPP=y >+CONFIG_ISDN_PPP_VJ=y >+CONFIG_ISDN_MPP=y >+CONFIG_ISDN_PPP_BSDCOMP=m >+# CONFIG_ISDN_AUDIO is not set >+ >+# >+# ISDN feature submodules >+# >+# CONFIG_ISDN_DRV_LOOP is not set >+# CONFIG_ISDN_DIVERSION is not set >+ >+# >+# low-level hardware drivers >+# >+ >+# >+# Passive ISDN cards >+# >+CONFIG_ISDN_DRV_HISAX=m >+CONFIG_ISDN_HISAX=y >+ >+# >+# D-channel protocol features >+# >+# CONFIG_HISAX_EURO is not set >+# CONFIG_HISAX_1TR6 is not set >+# CONFIG_HISAX_NI1 is not set >+CONFIG_HISAX_MAX_CARDS=8 >+ >+# >+# HiSax supported cards >+# >+# CONFIG_HISAX_TELESPCI is not set >+# CONFIG_HISAX_S0BOX is not set >+# CONFIG_HISAX_FRITZPCI is not set >+# CONFIG_HISAX_AVM_A1_PCMCIA is not set >+# CONFIG_HISAX_ELSA is not set >+# CONFIG_HISAX_DIEHLDIVA is not set >+# CONFIG_HISAX_SEDLBAUER is not set >+# CONFIG_HISAX_NETJET is not set >+# CONFIG_HISAX_NETJET_U is not set >+# CONFIG_HISAX_NICCY is not set >+# CONFIG_HISAX_BKM_A4T is not set >+# CONFIG_HISAX_SCT_QUADRO is not set >+CONFIG_HISAX_GAZEL=y >+# CONFIG_HISAX_HFC_PCI is not set >+# CONFIG_HISAX_W6692 is not set >+# CONFIG_HISAX_HFC_SX is not set >+# CONFIG_HISAX_ENTERNOW_PCI is not set >+# CONFIG_HISAX_DEBUG is not set >+# CONFIG_HISAX_SEDLBAUER_CS is not set >+# CONFIG_HISAX_ELSA_CS is not set >+# CONFIG_HISAX_AVM_A1_CS is not set >+CONFIG_HISAX_ST5481=m >+# CONFIG_HISAX_FRITZ_PCIPNP is not set >+# CONFIG_USB_AUERISDN is not set >+ >+# >+# Active ISDN cards >+# >+# CONFIG_ISDN_DRV_ICN is not set >+# CONFIG_ISDN_DRV_PCBIT is not set >+# CONFIG_ISDN_DRV_SC is not set >+# CONFIG_ISDN_DRV_ACT2000 is not set >+# CONFIG_ISDN_DRV_EICON is not set >+# CONFIG_ISDN_DRV_TPAM is not set >+# CONFIG_ISDN_CAPI is not set >+# CONFIG_HYSDN is not set >+# CONFIG_HYSDN_CAPI is not set > > # > # Old CD-ROM drivers (not SCSI, not IDE) >@@ -669,7 +764,7 @@ > # > CONFIG_FB=y > CONFIG_DUMMY_CONSOLE=y >-# CONFIG_FB_RIVA is not set >+CONFIG_FB_RIVA=y > # CONFIG_FB_CLGEN is not set > # CONFIG_FB_PM2 is not set > # CONFIG_FB_PM3 is not set >@@ -682,16 +777,7 @@ > CONFIG_FB_IMSTT=y > # CONFIG_FB_S3TRIO is not set > # CONFIG_FB_VGA16 is not set >-CONFIG_FB_MATROX=y >-CONFIG_FB_MATROX_MILLENIUM=y >-CONFIG_FB_MATROX_MYSTIQUE=y >-# CONFIG_FB_MATROX_G450 is not set >-CONFIG_FB_MATROX_G100A=y >-CONFIG_FB_MATROX_G100=y >-# CONFIG_FB_MATROX_I2C is not set >-# CONFIG_FB_MATROX_MAVEN is not set >-CONFIG_FB_MATROX_PROC=y >-# CONFIG_FB_MATROX_MULTIHEAD is not set >+# CONFIG_FB_MATROX is not set > CONFIG_FB_ATY=y > CONFIG_FB_ATY_GX=y > CONFIG_FB_ATY_CT=y >@@ -742,11 +828,11 @@ > CONFIG_PMAC_BACKLIGHT=y > CONFIG_MAC_FLOPPY=y > CONFIG_MAC_SERIAL=y >-# CONFIG_SERIAL_CONSOLE is not set >+CONFIG_SERIAL_CONSOLE=y > CONFIG_ADB=y > CONFIG_ADB_MACIO=y > CONFIG_INPUT_ADBHID=y >-CONFIG_MAC_ADBKEYCODES=y >+# CONFIG_MAC_ADBKEYCODES is not set > CONFIG_MAC_EMUMOUSEBTN=y > CONFIG_MAC_HID=y > # CONFIG_ANSLCD is not set >@@ -756,21 +842,23 @@ > # > CONFIG_VT=y > CONFIG_VT_CONSOLE=y >-CONFIG_SERIAL=m >+CONFIG_SERIAL=y >+CONFIG_SERIAL_CONSOLE=y > # CONFIG_SERIAL_EXTENDED is not set > # CONFIG_SERIAL_NONSTANDARD is not set > CONFIG_UNIX98_PTYS=y > CONFIG_UNIX98_PTY_COUNT=256 >+# CONFIG_BRIQ_PANEL is not set > > # > # I2C support > # >-CONFIG_I2C=m >+CONFIG_I2C=y > # CONFIG_I2C_ALGOBIT is not set > # CONFIG_I2C_ALGOPCF is not set >-CONFIG_I2C_KEYWEST=m >-CONFIG_I2C_CHARDEV=m >-CONFIG_I2C_PROC=m >+CONFIG_I2C_KEYWEST=y >+CONFIG_I2C_CHARDEV=y >+CONFIG_I2C_PROC=y > > # > # Mice >@@ -842,19 +930,59 @@ > # Ftape, the floppy tape device driver > # > # CONFIG_FTAPE is not set >-# CONFIG_AGP is not set >+CONFIG_AGP=m >+# CONFIG_AGP_INTEL is not set >+# CONFIG_AGP_I810 is not set >+# CONFIG_AGP_VIA is not set >+# CONFIG_AGP_AMD is not set >+# CONFIG_AGP_AMD_8151 is not set >+# CONFIG_AGP_SIS is not set >+# CONFIG_AGP_ALI is not set >+# CONFIG_AGP_SWORKS is not set >+CONFIG_AGP_UNINORTH=y > # CONFIG_DRM is not set > > # > # PCMCIA character devices > # >-# CONFIG_PCMCIA_SERIAL_CS is not set >+CONFIG_PCMCIA_SERIAL_CS=m > # CONFIG_SYNCLINK_CS is not set > > # > # Multimedia devices > # >-# CONFIG_VIDEO_DEV is not set >+CONFIG_VIDEO_DEV=m >+ >+# >+# Video For Linux >+# >+# CONFIG_VIDEO_PROC_FS is not set >+# CONFIG_I2C_PARPORT is not set >+ >+# >+# Video Adapters >+# >+# CONFIG_VIDEO_BT848 is not set >+# CONFIG_VIDEO_PMS is not set >+CONFIG_VIDEO_PLANB=m >+# CONFIG_VIDEO_CPIA is not set >+# CONFIG_VIDEO_SAA5249 is not set >+# CONFIG_TUNER_3036 is not set >+# CONFIG_VIDEO_STRADIS is not set >+# CONFIG_VIDEO_ZORAN is not set >+# CONFIG_VIDEO_ZORAN_BUZ is not set >+# CONFIG_VIDEO_ZORAN_DC10 is not set >+# CONFIG_VIDEO_ZORAN_LML33 is not set >+# CONFIG_VIDEO_ZR36120 is not set >+# CONFIG_VIDEO_MEYE is not set >+ >+# >+# Radio Adapters >+# >+# CONFIG_RADIO_GEMTEK_PCI is not set >+# CONFIG_RADIO_MAXIRADIO is not set >+# CONFIG_RADIO_MAESTRO is not set >+# CONFIG_RADIO_MIROPCM20 is not set > > # > # File systems >@@ -871,6 +999,7 @@ > CONFIG_HFS_FS=m > # CONFIG_BEFS_FS is not set > # CONFIG_BEFS_DEBUG is not set >+CONFIG_HFSPLUS_FS=m > # CONFIG_BFS_FS is not set > CONFIG_EXT3_FS=y > CONFIG_JBD=y >@@ -897,7 +1026,7 @@ > # CONFIG_NTFS_RW is not set > # CONFIG_HPFS_FS is not set > CONFIG_PROC_FS=y >-CONFIG_DEVFS_FS=y >+# CONFIG_DEVFS_FS is not set > # CONFIG_DEVFS_MOUNT is not set > # CONFIG_DEVFS_DEBUG is not set > CONFIG_DEVPTS_FS=y >@@ -963,7 +1092,7 @@ > # Native Language Support > # > CONFIG_NLS_DEFAULT="iso8859-1" >-# CONFIG_NLS_CODEPAGE_437 is not set >+CONFIG_NLS_CODEPAGE_437=m > # CONFIG_NLS_CODEPAGE_737 is not set > # CONFIG_NLS_CODEPAGE_775 is not set > # CONFIG_NLS_CODEPAGE_850 is not set >@@ -999,7 +1128,7 @@ > # CONFIG_NLS_ISO8859_15 is not set > # CONFIG_NLS_KOI8_R is not set > # CONFIG_NLS_KOI8_U is not set >-# CONFIG_NLS_UTF8 is not set >+CONFIG_NLS_UTF8=m > > # > # Sound >@@ -1007,8 +1136,6 @@ > CONFIG_SOUND=m > CONFIG_DMASOUND_PMAC=m > CONFIG_DMASOUND=m >-CONFIG_I2C=m >-CONFIG_I2C_KEYWEST=m > # CONFIG_SOUND_ALI5455 is not set > # CONFIG_SOUND_BT878 is not set > # CONFIG_SOUND_CMPCI is not set >@@ -1056,20 +1183,20 @@ > # > # USB Device Class drivers > # >-# CONFIG_USB_AUDIO is not set >+CONFIG_USB_AUDIO=m > # CONFIG_USB_EMI26 is not set > # CONFIG_USB_BLUETOOTH is not set > # CONFIG_USB_MIDI is not set >-# CONFIG_USB_STORAGE is not set >-# CONFIG_USB_STORAGE_DEBUG is not set >-# CONFIG_USB_STORAGE_DATAFAB is not set >-# CONFIG_USB_STORAGE_FREECOM is not set >-# CONFIG_USB_STORAGE_ISD200 is not set >-# CONFIG_USB_STORAGE_DPCM is not set >-# CONFIG_USB_STORAGE_HP8200e is not set >-# CONFIG_USB_STORAGE_SDDR09 is not set >-# CONFIG_USB_STORAGE_SDDR55 is not set >-# CONFIG_USB_STORAGE_JUMPSHOT is not set >+CONFIG_USB_STORAGE=m >+CONFIG_USB_STORAGE_DEBUG=y >+CONFIG_USB_STORAGE_DATAFAB=y >+CONFIG_USB_STORAGE_FREECOM=y >+CONFIG_USB_STORAGE_ISD200=y >+CONFIG_USB_STORAGE_DPCM=y >+CONFIG_USB_STORAGE_HP8200e=y >+CONFIG_USB_STORAGE_SDDR09=y >+CONFIG_USB_STORAGE_SDDR55=y >+CONFIG_USB_STORAGE_JUMPSHOT=y > CONFIG_USB_ACM=m > CONFIG_USB_PRINTER=m > >@@ -1078,7 +1205,7 @@ > # > CONFIG_USB_HID=y > CONFIG_USB_HIDINPUT=y >-# CONFIG_USB_HIDDEV is not set >+CONFIG_USB_HIDDEV=y > # CONFIG_USB_AIPTEK is not set > # CONFIG_USB_WACOM is not set > # CONFIG_USB_KBTAB is not set >@@ -1096,10 +1223,15 @@ > # > # USB Multimedia devices > # >- >-# >-# Video4Linux support is needed for USB Multimedia device support >-# >+# CONFIG_USB_IBMCAM is not set >+# CONFIG_USB_KONICAWC is not set >+CONFIG_USB_OV511=m >+CONFIG_USB_PWC=m >+# CONFIG_USB_SE401 is not set >+# CONFIG_USB_STV680 is not set >+# CONFIG_USB_VICAM is not set >+# CONFIG_USB_DSBR is not set >+# CONFIG_USB_DABUSB is not set > > # > # USB Network adaptors >@@ -1108,7 +1240,7 @@ > # CONFIG_USB_RTL8150 is not set > # CONFIG_USB_KAWETH is not set > # CONFIG_USB_CATC is not set >-# CONFIG_USB_CDCETHER is not set >+CONFIG_USB_CDCETHER=m > # CONFIG_USB_USBNET is not set > > # >@@ -1132,8 +1264,20 @@ > # CONFIG_USB_SERIAL_IR is not set > # CONFIG_USB_SERIAL_EDGEPORT is not set > # CONFIG_USB_SERIAL_EDGEPORT_TI is not set >-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set >-# CONFIG_USB_SERIAL_KEYSPAN is not set >+CONFIG_USB_SERIAL_KEYSPAN_PDA=m >+CONFIG_USB_SERIAL_KEYSPAN=m >+CONFIG_USB_SERIAL_KEYSPAN_USA28=y >+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y >+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y >+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y >+CONFIG_USB_SERIAL_KEYSPAN_USA19=y >+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y >+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y >+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y >+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y >+CONFIG_USB_SERIAL_KEYSPAN_MPR=y >+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y >+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y > # CONFIG_USB_SERIAL_MCT_U232 is not set > # CONFIG_USB_SERIAL_KLSI is not set > # CONFIG_USB_SERIAL_KOBIL_SCT is not set >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/Makefile linux-2.4.22-ppc-dev/arch/ppc/kernel/Makefile >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/Makefile 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/Makefile 2003-08-25 23:37:55.000000000 +0200 >@@ -45,7 +45,7 @@ > obj-$(CONFIG_PCI) += pci-dma.o > obj-$(CONFIG_KGDB) += ppc-stub.o > obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o >-obj-$(CONFIG_SMP) += smp.o >+obj-$(CONFIG_SMP) += smp.o smp-tbsync.o > obj-$(CONFIG_TAU) += temp.o > ifeq ($(CONFIG_SERIAL)$(CONFIG_GEN550),yy) > obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/btext.c linux-2.4.22-ppc-dev/arch/ppc/kernel/btext.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/btext.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/btext.c 2003-08-25 23:37:52.000000000 +0200 >@@ -42,22 +42,14 @@ > static unsigned char vga_font[cmapsz]; > > int boot_text_mapped; >+int force_printk_to_btext; > > boot_infos_t disp_bi; > > extern char *klimit; > >-/* >- * Powermac can use btext_* after boot for xmon, >- * chrp only uses it during early boot. >- */ >-#ifdef CONFIG_XMON >-#define BTEXT __pmac >-#define BTDATA __pmacdata >-#else >-#define BTEXT __init >-#define BTDATA __initdata >-#endif /* CONFIG_XMON */ >+#define BTEXT >+#define BTDATA > > /* > * This is called only when we are booted via BootX. >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/entry.S linux-2.4.22-ppc-dev/arch/ppc/kernel/entry.S >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/entry.S 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/entry.S 2003-08-25 23:37:35.000000000 +0200 >@@ -258,6 +258,12 @@ > addi r1,r1,INT_FRAME_SIZE > blr > >+ .globl syscall_direct_return >+syscall_direct_return: >+ addi r1,r3,-STACK_FRAME_OVERHEAD >+ /* XXX should check syscall tracing here */ >+ b ret_from_except >+ > .globl ret_from_fork > ret_from_fork: > bl schedule_tail >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/head.S linux-2.4.22-ppc-dev/arch/ppc/kernel/head.S >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/head.S 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/head.S 2003-08-25 23:37:38.000000000 +0200 >@@ -320,7 +320,7 @@ > DSSALL > sync > END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) >- STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) >+ STD_EXCEPTION(0x208, MachineCheck, MachineCheckException) > > /* Data access exception. */ > . = 0x300 >@@ -983,7 +983,9 @@ > /* enable use of AltiVec after return */ > oris r23,r23,MSR_VEC@h > mfspr r5,SPRG3 /* current task's THREAD (phys) */ >+ li r4,1 > li r20,THREAD_VSCR >+ stw r4,THREAD_USED_VR(r5) > LVX(vr0,r20,r5) > MTVSCR(vr0) > REST_32VR(0,r20,r5) >@@ -1712,7 +1714,7 @@ > > .globl intercept_table > intercept_table: >- .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700 >+ .long 0, 0, i0x208, i0x300, i0x400, 0, i0x600, i0x700 > .long i0x800, 0, 0, 0, 0, i0xd00, 0, 0 > .long 0, 0, 0, i0x1300, 0, 0, 0, 0 > .long 0, 0, 0, 0, 0, 0, 0, 0 >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/irq.c linux-2.4.22-ppc-dev/arch/ppc/kernel/irq.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/irq.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/irq.c 2003-08-25 23:37:34.000000000 +0200 >@@ -75,6 +75,10 @@ > unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; > atomic_t ppc_n_lost_interrupts; > >+#ifdef CONFIG_DEBUG_SPINLOCK >+int debug_long_irqlock; >+#endif /* CONFIG_DEBUG_SPINLOCK */ >+ > /* nasty hack for shared irq's since we need to do kmalloc calls but > * can't very early in the boot when we need to do a request irq. > * this needs to be removed. >@@ -578,6 +582,24 @@ > unsigned long *stack; > int cpu = smp_processor_id(); > >+#ifdef CONFIG_XMON >+ xmon_printf("\n%s, CPU %d:\n", str, cpu); >+ xmon_printf("irq: %d [%d %d]\n", >+ atomic_read(&global_irq_count), >+ local_irq_count(0), >+ local_irq_count(1)); >+ xmon_printf("bh: %d [%d %d]\n", >+ atomic_read(&global_bh_count), >+ local_bh_count(0), >+ local_bh_count(1)); >+ stack = (unsigned long *) &str; >+ for (i = 40; i ; i--) { >+ unsigned long x = *++stack; >+ if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { >+ xmon_printf("<[%08lx]> ", x); >+ } >+ } >+#endif /* CONFIG_XMON */ > printk("\n%s, CPU %d:\n", str, cpu); > printk("irq: %d [%d %d]\n", > atomic_read(&global_irq_count), >@@ -694,6 +716,9 @@ > do { > do { > if (loops-- == 0) { >+#ifdef CONFIG_XMON >+ xmon_printf("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder); >+#endif > printk("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder); > #ifdef CONFIG_XMON > xmon(0); >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/m8xx_setup.c linux-2.4.22-ppc-dev/arch/ppc/kernel/m8xx_setup.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/m8xx_setup.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/m8xx_setup.c 2003-08-25 23:37:46.000000000 +0200 >@@ -43,6 +43,7 @@ > #include <asm/machdep.h> > #include <asm/bootinfo.h> > #include <asm/time.h> >+#include <asm/i8259.h> > > #include "ppc8xx_pic.h" > >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/misc.S linux-2.4.22-ppc-dev/arch/ppc/kernel/misc.S >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/misc.S 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/misc.S 2003-08-25 23:37:35.000000000 +0200 >@@ -200,6 +200,59 @@ > mr r4,r24 > bctr > >+#ifdef CONFIG_CPU_FREQ_PMAC >+ >+/* This gets called by via-pmu.c to switch the PLL selection >+ * on 750fx CPU. >+ */ >+_GLOBAL(low_choose_750fx_pll) >+ /* Clear MSR:EE */ >+ mfmsr r7 >+ rlwinm r0,r7,0,17,15 >+ mtmsr r0 >+ >+ /* If switching to PLL1, disable HID0:BTIC */ >+ cmpli cr0,r3,0 >+ beq 1f >+ mfspr r5,HID0 >+ rlwinm r5,r5,0,27,25 >+ sync >+ mtspr HID0,r5 >+ isync >+ sync >+ >+1: >+ /* Calc new HID1 value */ >+ mfspr r4,SPRN_HID1 /* Build a HID1:PS bit from parameter */ >+ rlwinm r5,r3,16,15,15 /* Clear out HID1:PS from value read */ >+ rlwinm r4,r4,0,16,14 /* Could have I used rlwimi here ? */ >+ or r4,r4,r5 >+ mtspr SPRN_HID1,r4 >+ >+ /* Store new HID1 image */ >+ lwz r6,PROCESSOR(r2) >+ slwi r6,r6,2 >+ addis r6,r6,nap_save_hid1@ha >+ stw r4,nap_save_hid1@l(r6) >+ >+ /* If switching to PLL0, enable HID0:BTIC */ >+ cmpli cr0,r3,0 >+ bne 1f >+ mfspr r5,HID0 >+ ori r5,r5,HID0_BTIC >+ sync >+ mtspr HID0,r5 >+ isync >+ sync >+ >+1: >+ /* Return */ >+ mtmsr r7 >+ blr >+ >+#endif /* CONFIG_CPU_FREQ_PMAC */ >+ >+ > /* void __save_flags_ptr(unsigned long *flags) */ > _GLOBAL(__save_flags_ptr) > mfmsr r4 >@@ -1243,6 +1296,24 @@ > .long sys_ni_syscall /* reserved for sys_io_getevents */ > .long sys_ni_syscall /* 230 reserved for sys_io_submit */ > .long sys_ni_syscall /* reserved for sys_io_cancel */ >+ .long sys_ni_syscall /* reserved for sys_set_tid_address */ >+ .long sys_ni_syscall /* reserved for sys_fadvise64 */ >+ .long sys_ni_syscall /* reserved for sys_exit_group */ >+ .long sys_ni_syscall /* 235 reserved for sys_lookup_dcookie */ >+ .long sys_ni_syscall /* reserved for sys_epoll_create */ >+ .long sys_ni_syscall /* reserved for sys_epoll_ctl */ >+ .long sys_ni_syscall /* reserved for sys_epoll_wait */ >+ .long sys_ni_syscall /* reserved for sys_remap_file_pages */ >+ .long sys_ni_syscall /* 240 reserved for sys_timer_create */ >+ .long sys_ni_syscall /* reserved for sys_timer_settime */ >+ .long sys_ni_syscall /* reserved for sys_timer_gettime */ >+ .long sys_ni_syscall /* reserved for sys_timer_getoverrun */ >+ .long sys_ni_syscall /* reserved for sys_timer_delete */ >+ .long sys_ni_syscall /* 245 reserved for sys_clock_settime */ >+ .long sys_ni_syscall /* reserved for sys_clock_gettime */ >+ .long sys_ni_syscall /* reserved for sys_clock_getres */ >+ .long sys_ni_syscall /* reserved for sys_clock_nanosleep */ >+ .long sys_swapcontext > > .rept NR_syscalls-(.-sys_call_table)/4 > .long sys_ni_syscall >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/mk_defs.c linux-2.4.22-ppc-dev/arch/ppc/kernel/mk_defs.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/mk_defs.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/mk_defs.c 2003-08-25 23:37:48.000000000 +0200 >@@ -56,6 +56,7 @@ > DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); > DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); > DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); >+ DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); > #endif /* CONFIG_ALTIVEC */ > #ifdef CONFIG_4xx > DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/open_pic.c linux-2.4.22-ppc-dev/arch/ppc/kernel/open_pic.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/open_pic.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/open_pic.c 2003-08-25 23:37:57.000000000 +0200 >@@ -870,6 +870,17 @@ > static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES]; > static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS]; > >+static void openpic_cached_enable_irq(u_int irq) >+{ >+ check_arg_irq(irq); >+ save_irq_src_vp[irq - open_pic_irq_offset] &= ~OPENPIC_MASK; >+} >+ >+static void openpic_cached_disable_irq(u_int irq) >+{ >+ check_arg_irq(irq); >+ save_irq_src_vp[irq - open_pic_irq_offset] |= OPENPIC_MASK; >+} > void __pmac > openpic_sleep_save_intrs(void) > { >@@ -878,6 +889,9 @@ > > spin_lock_irqsave(&openpic_setup_lock, flags); > >+ open_pic.enable = openpic_cached_enable_irq; >+ open_pic.disable = openpic_cached_disable_irq; >+ > for (i=0; i<NumProcessors; i++) { > save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority); > openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority, >@@ -921,6 +935,9 @@ > openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, > save_cpu_task_pri[i]); > >+ open_pic.enable = openpic_enable_irq; >+ open_pic.disable = openpic_disable_irq; >+ > spin_unlock_irqrestore(&openpic_setup_lock, flags); > } > #endif /* CONFIG_PMAC_PBOOK */ >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/pci.c linux-2.4.22-ppc-dev/arch/ppc/kernel/pci.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/pci.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/pci.c 2003-08-25 23:38:04.000000000 +0200 >@@ -1,5 +1,5 @@ > /* >- * Common pmac/prep/chrp pci routines. -- Cort >+ * Common PCI code for PPC architecture > */ > > #include <linux/config.h> >@@ -22,7 +22,7 @@ > #include <asm/irq.h> > #include <asm/uaccess.h> > >-#undef DEBUG >+#define DEBUG > > #ifdef DEBUG > #define DBG(x...) printk(x) >@@ -116,6 +116,10 @@ > struct pci_controller* hose = dev->sysdata; > unsigned long io_offset; > >+ if (dev->vendor == PCI_VENDOR_ID_APPLE && dev->device == PCI_DEVICE_ID_APPLE_KEYLARGO) { >+ printk("trying to reloc keylargo !! skipping\n"); >+ return; >+ } > new = res->start; > res->flags &= ~IORESOURCE_UNSET; > if (hose && res->flags & IORESOURCE_IO) { >@@ -217,7 +221,8 @@ > } > if (dev->device == PCI_DEVICE_ID_TI_1210 || > dev->device == PCI_DEVICE_ID_TI_1211 || >- dev->device == PCI_DEVICE_ID_TI_1410) { >+ dev->device == PCI_DEVICE_ID_TI_1410 || >+ dev->device == PCI_DEVICE_ID_TI_1510) { > u8 val; > /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA > signal out the MFUNC0 pin */ >@@ -563,8 +568,9 @@ > { > struct resource *pr, *r = &dev->resource[idx]; > >- DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n", >- dev->slot_name, idx, r->start, r->end, r->flags); >+ DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx), vd: %04x, dev: %04x\n", >+ dev->slot_name, idx, r->start, r->end, r->flags, >+ dev->vendor, dev->device); > pr = pci_find_parent_resource(dev, r); > if (!pr || request_resource(pr, r) < 0) { > printk(KERN_ERR "PCI: Cannot allocate resource region %d" >@@ -1029,6 +1035,10 @@ > } > ranges += np; > } >+ DBG("hose %s, pci_mem_offset: %08lx, start0: %08lx\n", >+ dev->name, hose->pci_mem_offset, hose->mem_resources[0].start); >+ DBG(" io_base_virt: %p, io_base_phys: %08lx, isa_mem_base: %08lx\n", >+ hose->io_base_virt, hose->io_base_phys, isa_mem_base); > } > > /* We create the "pci-OF-bus-map" property now so it appears in the >@@ -1341,6 +1351,9 @@ > return PCI_SLOT(dev->devfn); > } > >+/* Where does that come from ? Doesn't seem to be correct for us, but we >+ * don't use it anyway so ... -BenH. >+ */ > void __init > pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) > { >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/ppc_ksyms.c linux-2.4.22-ppc-dev/arch/ppc/kernel/ppc_ksyms.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/ppc_ksyms.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/ppc_ksyms.c 2003-08-25 23:37:36.000000000 +0200 >@@ -14,6 +14,7 @@ > #include <linux/irq.h> > #include <linux/pci.h> > #include <linux/delay.h> >+#include <linux/vmalloc.h> > #include <linux/ide.h> > > #include <asm/page.h> >@@ -67,9 +68,10 @@ > extern int pmac_newworld; > extern int sys_sigreturn(struct pt_regs *regs); > >-long long __ashrdi3(long long, int); >-long long __ashldi3(long long, int); >-long long __lshrdi3(long long, int); >+extern long long __ashrdi3(long long, int); >+extern long long __ashldi3(long long, int); >+extern long long __lshrdi3(long long, int); >+ > int abs(int); > > extern unsigned char __res[]; >@@ -128,7 +130,6 @@ > EXPORT_SYMBOL(strcmp); > EXPORT_SYMBOL(strncmp); > EXPORT_SYMBOL(strcasecmp); >-EXPORT_SYMBOL(__div64_32); > > /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */ > EXPORT_SYMBOL(csum_partial_copy_generic); >@@ -192,6 +193,7 @@ > EXPORT_SYMBOL(flush_icache_user_range); > EXPORT_SYMBOL(flush_icache_page); > EXPORT_SYMBOL(flush_dcache_page); >+EXPORT_SYMBOL(local_flush_tlb_page); > EXPORT_SYMBOL(xchg_u32); > #ifdef CONFIG_ALTIVEC > EXPORT_SYMBOL(last_task_used_altivec); >@@ -288,6 +290,7 @@ > EXPORT_SYMBOL_NOVERS(memscan); > EXPORT_SYMBOL_NOVERS(memcmp); > EXPORT_SYMBOL_NOVERS(memchr); >+EXPORT_SYMBOL_NOVERS(__div64_32); > > EXPORT_SYMBOL(abs); > >@@ -314,7 +317,7 @@ > EXPORT_SYMBOL(get_wchan); > EXPORT_SYMBOL(console_drivers); > #ifdef CONFIG_XMON >-extern void xmon_printf(char *fmt, ...); >+extern void xmon_printf(const char *fmt, ...); > EXPORT_SYMBOL(xmon); > EXPORT_SYMBOL(xmon_printf); > #endif >@@ -367,6 +370,10 @@ > EXPORT_SYMBOL(ret_from_intercept); > EXPORT_SYMBOL(cur_cpu_spec); > #if defined(CONFIG_ALL_PPC) >+extern int map_page(unsigned long va, unsigned long pa, int flags); >+ >+EXPORT_SYMBOL(map_page); >+EXPORT_SYMBOL(get_vm_area); > extern unsigned long agp_special_page; > EXPORT_SYMBOL_NOVERS(agp_special_page); > #endif /* defined(CONFIG_ALL_PPC) */ >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/process.c linux-2.4.22-ppc-dev/arch/ppc/kernel/process.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/process.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/process.c 2003-08-25 23:37:33.000000000 +0200 >@@ -417,6 +417,7 @@ > memset(current->thread.vr, 0, sizeof(current->thread.vr)); > memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr)); > current->thread.vrsave = 0; >+ current->thread.used_vr = 0; > #endif /* CONFIG_ALTIVEC */ > } > >@@ -506,14 +507,19 @@ > if (sp == NULL) > asm("mr %0,1" : "=r" (sp)); > printk("Call backtrace: "); >+ if (sp == NULL) >+ sp = (unsigned long *)_get_SP(); > while (sp) { >- if (__get_user( i, &sp[1] )) >+ if (__get_user(sp, (unsigned long **)sp)) >+ break; >+ if (sp == NULL) >+ break; >+ if (__get_user(i, &sp[1])) > break; > if (cnt++ % 7 == 0) > printk("\n"); > printk("%08lX ", i); >- if (cnt > 32) break; >- if (__get_user(sp, (unsigned long **)sp)) >+ if (cnt > 32) > break; > } > printk("\n"); >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/setup.c linux-2.4.22-ppc-dev/arch/ppc/kernel/setup.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/setup.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/setup.c 2003-08-25 23:37:52.000000000 +0200 >@@ -52,6 +52,7 @@ > struct ide_machdep_calls ppc_ide_md; > char *sysmap; > unsigned long sysmap_size; >+int no_nap; > > /* Used with the BI_MEMSIZE bootinfo parameter to store the memory > size value reported by the boot loader. */ >@@ -152,7 +153,7 @@ > return 0; > pvr = cpu_data[i].pvr; > lpj = cpu_data[i].loops_per_jiffy; >- seq_printf(m, "processor\t: %lu\n", i); >+ seq_printf(m, "processor\t: %u\n", i); > #else > pvr = mfspr(PVR); > lpj = loops_per_jiffy; >@@ -329,6 +330,7 @@ > unsigned long r6, unsigned long r7) > { > #ifdef CONFIG_BOOTX_TEXT >+ extern int force_printk_to_btext; > if (boot_text_mapped) { > btext_clearscreen(); > btext_welcome(); >@@ -415,6 +417,27 @@ > } > cmd_line[sizeof(cmd_line) - 1] = 0; > >+ /* Debug stuff, do not merge ! */ >+#ifdef CONFIG_ADB_PMU >+ if (strstr(cmd_line, "fake_sleep")) { >+ extern int __fake_sleep; >+ __fake_sleep = 1; >+ } >+#endif /* CONFIG_ADB_PMU */ >+#ifdef CONFIG_ADB >+ if (strstr(cmd_line, "adb_sync")) { >+ extern int __adb_probe_sync; >+ __adb_probe_sync = 1; >+ } >+#endif /* CONFIG_ADB */ >+ if (strstr(cmd_line, "nol3") && cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) >+ _set_L3CR(0); >+ if (strstr(cmd_line, "nonap")) >+ cur_cpu_spec[0]->cpu_features &= ~CPU_FTR_CAN_NAP; >+#ifdef CONFIG_BOOTX_TEXT >+ if (strstr(cmd_line, "printkbtext")) >+ force_printk_to_btext = 1; >+#endif > switch (_machine) { > case _MACH_Pmac: > pmac_init(r3, r4, r5, r6, r7); >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/signal.c linux-2.4.22-ppc-dev/arch/ppc/kernel/signal.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/signal.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/signal.c 2003-08-25 23:37:53.000000000 +0200 >@@ -40,17 +40,7 @@ > > #define GP_REGS_SIZE MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs)) > >-/* >- * These are the flags in the MSR that the user is allowed to change >- * by modifying the saved value of the MSR on the stack. SE and BE >- * should not be in this list since gdb may want to change these. I.e, >- * you should be able to step out of a signal handler to see what >- * instruction executes next after the signal handler completes. >- * Alternately, if you stepped into a signal handler, you should be >- * able to continue 'til the next breakpoint from within the signal >- * handler, even if the handler returns. >- */ >-#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) >+extern void syscall_direct_return(struct pt_regs *regs); > > int do_signal(sigset_t *oldset, struct pt_regs *regs); > >@@ -117,7 +107,7 @@ > * do_signal() has set R3 to the signal number (the > * first argument of the signal handler), so don't > * overwrite that with EINTR ! >- * In the other cases, do_signal() doesn't touch >+ * In the other cases, do_signal() doesn't touch > * R3, so it's still set to -EINTR (see above). > */ > return regs->gpr[3]; >@@ -157,13 +147,13 @@ > > > int >-sys_sigaltstack(const stack_t *uss, stack_t *uoss) >+sys_sigaltstack(const stack_t *uss, stack_t *uoss, int r5, int r6, >+ int r7, int r8, struct pt_regs *regs) > { >- struct pt_regs *regs = (struct pt_regs *) &uss; > return do_sigaltstack(uss, uoss, regs->gpr[1]); > } > >-int >+int > sys_sigaction(int sig, const struct old_sigaction *act, > struct old_sigaction *oact) > { >@@ -199,270 +189,303 @@ > * When we have signals to deliver, we set up on the > * user stack, going down from the original stack pointer: > * a sigregs struct >- * one or more sigcontext structs with >+ * a sigcontext struct > * a gap of __SIGNAL_FRAMESIZE bytes > * > * Each of these things must be a multiple of 16 bytes in size. > * > */ > struct sigregs { >- elf_gregset_t gp_regs; >- double fp_regs[ELF_NFPREG]; >- unsigned long tramp[2]; >+ struct mcontext mctx; /* all the register values */ > /* Programs using the rs6000/xcoff abi can save up to 19 gp regs > and 18 fp regs below sp before decrementing it. */ > int abigap[56]; > }; > >-struct rt_sigframe >-{ >- unsigned long _unused[2]; >- struct siginfo *pinfo; >- void *puc; >- struct siginfo info; >- struct ucontext uc; >-}; >- >+/* We use the mc_pad field for the signal return trampoline. */ >+#define tramp mc_pad > > /* > * When we have rt signals to deliver, we set up on the > * user stack, going down from the original stack pointer: >- * a sigregs struct >- * one rt_sigframe struct (siginfo + ucontext) >- * a gap of __SIGNAL_FRAMESIZE bytes >+ * one rt_sigframe struct (siginfo + ucontext + ABI gap) >+ * a gap of __SIGNAL_FRAMESIZE+16 bytes >+ * (the +16 is to get the siginfo and ucontext in the same >+ * positions as in older kernels). > * > * Each of these things must be a multiple of 16 bytes in size. > * > */ >-int sys_rt_sigreturn(struct pt_regs *regs) >+struct rt_sigframe > { >- struct rt_sigframe *rt_sf; >- struct sigcontext_struct sigctx; >- struct sigregs *sr; >- int ret; >- elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ >- sigset_t set; >- stack_t st; >- unsigned long prevsp; >+ struct siginfo info; >+ struct ucontext uc; >+ /* Programs using the rs6000/xcoff abi can save up to 19 gp regs >+ and 18 fp regs below sp before decrementing it. */ >+ int abigap[56]; >+}; > >- rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); >- if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) >- || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) >- || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) >- goto badframe; >- sigdelsetmask(&set, ~_BLOCKABLE); >- spin_lock_irq(¤t->sigmask_lock); >- current->blocked = set; >- recalc_sigpending(current); >- spin_unlock_irq(¤t->sigmask_lock); >+/* >+ * Save the current user registers on the user stack. >+ * We only save the altivec registers if the process has used >+ * altivec instructions at some point. >+ */ >+static int >+save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret, int mctxsize) >+{ >+ if (mctxsize && mctxsize < sizeof(struct mcontext)) >+ return 1; >+ >+ /* save general and floating-point registers */ > if (regs->msr & MSR_FP) > giveup_fpu(current); >+ if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE) >+ || __copy_to_user(&frame->mc_fregs, current->thread.fpr, >+ ELF_NFPREG * sizeof(double))) >+ return 1; > >- rt_sf++; /* Look at next rt_sigframe */ >- if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) { >- /* Last stacked signal - restore registers - >- * sigctx is initialized to point to the >- * preamble frame (where registers are stored) >- * see handle_signal() >- */ >- sr = (struct sigregs *) sigctx.regs; >- if (copy_from_user(saved_regs, &sr->gp_regs, >- sizeof(sr->gp_regs))) >- goto badframe; >- saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) >- | (saved_regs[PT_MSR] & MSR_USERCHANGE); >- memcpy(regs, saved_regs, GP_REGS_SIZE); >- if (copy_from_user(current->thread.fpr, &sr->fp_regs, >- sizeof(sr->fp_regs))) >- goto badframe; >- /* This function sets back the stack flags into >- the current task structure. */ >- sys_sigaltstack(&st, NULL); >- >- ret = regs->result; >- } else { >- /* More signals to go */ >- /* Set up registers for next signal handler */ >- regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE; >- if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))) >- goto badframe; >- sr = (struct sigregs *) sigctx.regs; >- regs->gpr[3] = ret = sigctx.signal; >- /* Get the siginfo */ >- get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo); >- /* Get the ucontext */ >- get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc); >- regs->gpr[6] = (unsigned long) rt_sf; >- >- regs->link = (unsigned long) &sr->tramp; >- regs->nip = sigctx.handler; >- if (get_user(prevsp, &sr->gp_regs[PT_R1]) >- || put_user(prevsp, (unsigned long *) regs->gpr[1])) >- goto badframe; >- current->thread.fpscr = 0; >+ current->thread.fpscr = 0; /* turn off all fp exceptions */ >+ >+#ifdef CONFIG_ALTIVEC >+ /* save altivec registers */ >+ if (current->thread.used_vr) { >+ if (regs->msr & MSR_VEC) >+ giveup_altivec(current); >+ if (__copy_to_user(&frame->mc_vregs, current->thread.vr, >+ ELF_NVRREG * sizeof(vector128))) >+ return 1; >+ /* set MSR_VEC in the saved MSR value to indicate that >+ frame->mc_vregs contains valid data */ >+ if (__put_user(regs->msr | MSR_VEC, &frame->mc_gregs[PT_MSR])) >+ return 1; >+ } >+ /* else assert((regs->msr & MSR_VEC) == 0) */ >+ >+ /* We always copy to/from vrsave, it's 0 if we don't have or don't >+ * use altivec. Since VSCR only contains 32 bits saved in the least >+ * significant bits of a vector, we "cheat" and stuff VRSAVE in the >+ * most significant bits of that same vector. --BenH >+ */ >+ if (__put_user(current->thread.vrsave, (u32 *)&frame->mc_vregs[32])) >+ return 1; >+#endif /* CONFIG_ALTIVEC */ >+ >+ if (sigret) { >+ /* Set up the sigreturn trampoline: li r0,sigret; sc */ >+ if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) >+ || __put_user(0x44000002UL, &frame->tramp[1])) >+ return 1; >+ flush_icache_range((unsigned long) &frame->tramp[0], >+ (unsigned long) &frame->tramp[2]); > } >- return ret; > >-badframe: >- do_exit(SIGSEGV); >+ return 0; > } > >+/* >+ * Restore the current user register values from the user stack, >+ * (except for MSR). >+ */ >+static int >+restore_user_regs(struct pt_regs *regs, struct mcontext *sr, int mctxsize) >+{ >+#ifdef CONFIG_ALTIVEC >+ unsigned long msr; >+#endif >+ >+ if (mctxsize && mctxsize < sizeof(struct mcontext)) >+ return 1; >+ >+ /* copy up to but not including MSR */ >+ if (__copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t))) >+ return 1; >+ /* copy from orig_r3 (the word after the MSR) up to the end */ >+ if (__copy_from_user(®s->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3], >+ GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t))) >+ return 1; >+ >+ /* force the process to reload the FP registers from >+ current->thread when it next does FP instructions */ >+ regs->msr &= ~MSR_FP; >+ if (__copy_from_user(current->thread.fpr, &sr->mc_fregs, >+ sizeof(sr->mc_fregs))) >+ return 1; >+ >+#ifdef CONFIG_ALTIVEC >+ /* force the process to reload the altivec registers from >+ current->thread when it next does altivec instructions */ >+ regs->msr &= ~MSR_VEC; >+ if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) { >+ /* restore altivec registers from the stack */ >+ if (__copy_from_user(current->thread.vr, &sr->mc_vregs, >+ sizeof(sr->mc_vregs))) >+ return 1; >+ } else if (current->thread.used_vr) >+ memset(¤t->thread.vr, 0, sizeof(current->thread.vr)); >+ >+ /* Always get VRSAVE back */ >+ if (__get_user(current->thread.vrsave, (u32 *)&sr->mc_vregs[32])) >+ return 1; >+#endif /* CONFIG_ALTIVEC */ >+ >+ return 0; >+} >+ >+/* >+ * Restore the user process's signal mask >+ */ > static void >-setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, >- signed long newsp) >+restore_sigmask(sigset_t *set) > { >- struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp; >+ sigdelsetmask(set, ~_BLOCKABLE); >+ spin_lock_irq(¤t->sigmask_lock); >+ current->blocked = *set; >+ recalc_sigpending(current); >+ spin_unlock_irq(¤t->sigmask_lock); >+} > >- /* Set up preamble frame */ >- if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) >+/* >+ * Set up a signal frame for a "real-time" signal handler >+ * (one which gets siginfo). >+ */ >+static void >+handle_rt_signal(unsigned long sig, struct k_sigaction *ka, >+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, >+ unsigned long newsp) >+{ >+ struct rt_sigframe *rt_sf; >+ struct mcontext *frame; >+ unsigned long origsp = newsp; >+ >+ /* Set up Signal Frame */ >+ /* Put a Real Time Context onto stack */ >+ newsp -= sizeof(*rt_sf); >+ rt_sf = (struct rt_sigframe *) newsp; >+ >+ /* create a stack frame for the caller of the handler */ >+ newsp -= __SIGNAL_FRAMESIZE + 16; >+ >+ if (verify_area(VERIFY_WRITE, (void *) newsp, origsp - newsp)) > goto badframe; >- if (regs->msr & MSR_FP) >- giveup_fpu(current); >- if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) >- || __copy_to_user(&frame->fp_regs, current->thread.fpr, >- ELF_NFPREG * sizeof(double)) >- /* Set up to return from user space. >- It calls the sc exception at offset 0x9999 >- for sys_rt_sigreturn(). >- */ >- || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */ >- || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ >+ >+ /* Put the siginfo & fill in most of the ucontext */ >+ if (__copy_to_user(&rt_sf->info, info, sizeof(*info)) >+ || __put_user(0, &rt_sf->uc.uc_flags) >+ || __put_user(0, &rt_sf->uc.uc_link) >+ || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) >+ || __put_user(sas_ss_flags(regs->gpr[1]), >+ &rt_sf->uc.uc_stack.ss_flags) >+ || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) >+ || __put_user(&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs) >+ || __copy_to_user(&rt_sf->uc.uc_oldsigmask, oldset, sizeof(*oldset)) >+ || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))) > goto badframe; >- flush_icache_range((unsigned long) &frame->tramp[0], >- (unsigned long) &frame->tramp[2]); >- current->thread.fpscr = 0; /* turn off all fp exceptions */ > >- /* Retrieve rt_sigframe from stack and >- set up registers for signal handler >- */ >- newsp -= __SIGNAL_FRAMESIZE; >- if (put_user(regs->gpr[1], (unsigned long *)newsp) >- || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler) >- || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) >- || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo) >- || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc)) >+ /* Save user registers on the stack */ >+ frame = &rt_sf->uc.uc_mcontext; >+ if (save_user_regs(regs, frame, 0x6666, 0)) > goto badframe; > >+ if (put_user(regs->gpr[1], (unsigned long *)newsp)) >+ goto badframe; > regs->gpr[1] = newsp; >+ regs->gpr[3] = sig; >+ regs->gpr[4] = (unsigned long) &rt_sf->info; >+ regs->gpr[5] = (unsigned long) &rt_sf->uc; > regs->gpr[6] = (unsigned long) rt_sf; >+ regs->nip = (unsigned long) ka->sa.sa_handler; > regs->link = (unsigned long) frame->tramp; > > return; > > badframe: > #if DEBUG_SIG >- printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", >+ printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", > regs, frame, newsp); > #endif > do_exit(SIGSEGV); > } > >-/* >- * Do a signal return; undo the signal stack. >- */ >-int sys_sigreturn(struct pt_regs *regs) >+static int do_setcontext(struct ucontext *ucp, struct pt_regs *regs, int mctxsize) > { >- struct sigcontext_struct *sc, sigctx; >- struct sigregs *sr; >- int ret; >- elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ > sigset_t set; >- unsigned long prevsp; > >- sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); >- if (copy_from_user(&sigctx, sc, sizeof(sigctx))) >- goto badframe; >+ if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(set))) >+ return -EFAULT; >+ restore_sigmask(&set); > >- set.sig[0] = sigctx.oldmask; >-#if _NSIG_WORDS > 1 >- set.sig[1] = sigctx._unused[3]; >-#endif >- sigdelsetmask(&set, ~_BLOCKABLE); >- spin_lock_irq(¤t->sigmask_lock); >- current->blocked = set; >- recalc_sigpending(current); >- spin_unlock_irq(¤t->sigmask_lock); >- if (regs->msr & MSR_FP ) >- giveup_fpu(current); >+ if (restore_user_regs(regs, &ucp->uc_mcontext, mctxsize)) >+ return -EFAULT; > >- sc++; /* Look at next sigcontext */ >- if (sc == (struct sigcontext_struct *)(sigctx.regs)) { >- /* Last stacked signal - restore registers */ >- sr = (struct sigregs *) sigctx.regs; >- if (copy_from_user(saved_regs, &sr->gp_regs, >- sizeof(sr->gp_regs))) >- goto badframe; >- saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) >- | (saved_regs[PT_MSR] & MSR_USERCHANGE); >- memcpy(regs, saved_regs, GP_REGS_SIZE); >- >- if (copy_from_user(current->thread.fpr, &sr->fp_regs, >- sizeof(sr->fp_regs))) >- goto badframe; >- >- ret = regs->result; >- >- } else { >- /* More signals to go */ >- regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE; >- if (copy_from_user(&sigctx, sc, sizeof(sigctx))) >- goto badframe; >- sr = (struct sigregs *) sigctx.regs; >- regs->gpr[3] = ret = sigctx.signal; >- regs->gpr[4] = (unsigned long) sc; >- regs->link = (unsigned long) &sr->tramp; >- regs->nip = sigctx.handler; >- >- if (get_user(prevsp, &sr->gp_regs[PT_R1]) >- || put_user(prevsp, (unsigned long *) regs->gpr[1])) >- goto badframe; >- current->thread.fpscr = 0; >+ return 0; >+} >+ >+int sys_swapcontext(struct ucontext *old_ctx, struct ucontext *new_ctx, >+ int mctxtsize, int r6, int r7, int r8, struct pt_regs *regs) >+{ >+ unsigned char tmp; >+ >+ if (old_ctx != NULL) { >+ if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) >+ || save_user_regs(regs, &old_ctx->uc_mcontext, 0, mctxtsize) >+ || __copy_to_user(&old_ctx->uc_sigmask, >+ ¤t->blocked, sizeof(sigset_t)) >+ /* the next 2 things aren't strictly necessary */ >+ || __copy_to_user(&old_ctx->uc_oldsigmask, >+ ¤t->blocked, sizeof(sigset_t)) >+ || __put_user(&old_ctx->uc_mcontext, &old_ctx->uc_regs)) >+ return -EFAULT; > } >- return ret; >+ if (new_ctx == NULL) >+ return 0; >+ if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx)) >+ || __get_user(tmp, (u8 *) new_ctx) >+ || __get_user(tmp, (u8 *) (new_ctx + 1) - 1)) >+ return -EFAULT; > >-badframe: >- do_exit(SIGSEGV); >+ /* >+ * If we get a fault copying the context into the kernel's >+ * image of the user's registers, we can't just return -EFAULT >+ * because the user's registers will be corrupted. For instance >+ * the NIP value may have been updated but not some of the >+ * other registers. Given that we have done the verify_area >+ * and successfully read the first and last bytes of the region >+ * above, this should only happen in an out-of-memory situation >+ * or if another thread unmaps the region containing the context. >+ * We kill the task with a SIGSEGV in this situation. >+ */ >+ if (do_setcontext(new_ctx, regs, mctxtsize)) >+ do_exit(SIGSEGV); >+ syscall_direct_return(regs); >+ /* doesn't actually return back to here */ >+ return 0; > } > >-/* >- * Set up a signal frame. >- */ >-static void >-setup_frame(struct pt_regs *regs, struct sigregs *frame, >- unsigned long newsp) >+int sys_rt_sigreturn(struct pt_regs *regs) > { >- struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp; >+ struct rt_sigframe *rt_sf; >+ stack_t st; > >- if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) >- goto badframe; >- if (regs->msr & MSR_FP) >- giveup_fpu(current); >- if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) >- || __copy_to_user(&frame->fp_regs, current->thread.fpr, >- ELF_NFPREG * sizeof(double)) >- || __put_user(0x38007777UL, &frame->tramp[0]) /* li r0,0x7777 */ >- || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ >- goto badframe; >- flush_icache_range((unsigned long) &frame->tramp[0], >- (unsigned long) &frame->tramp[2]); >- current->thread.fpscr = 0; /* turn off all fp exceptions */ >+ rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16); >+ if (verify_area(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe))) >+ goto bad; >+ if (do_setcontext(&rt_sf->uc, regs, 0)) >+ goto bad; >+ >+ /* >+ * It's not clear whether or why it is desirable to save the >+ * sigaltstack setting on signal delivery and restore it on >+ * signal return. But other architectures do this and we have >+ * always done it up until now so it is probably better not to >+ * change it. -- paulus >+ */ >+ if (__copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) >+ goto bad; >+ do_sigaltstack(&st, NULL, regs->gpr[1]); > >- newsp -= __SIGNAL_FRAMESIZE; >- if (put_user(regs->gpr[1], (unsigned long *)newsp) >- || get_user(regs->nip, &sc->handler) >- || get_user(regs->gpr[3], &sc->signal)) >- goto badframe; >- regs->gpr[1] = newsp; >- regs->gpr[4] = (unsigned long) sc; >- regs->link = (unsigned long) frame->tramp; >+ return regs->result; > >- return; >- >-badframe: >-#if DEBUG_SIG >- printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", >- regs, frame, newsp); >-#endif >+ bad: > do_exit(SIGSEGV); > } > >@@ -472,69 +495,47 @@ > static void > handle_signal(unsigned long sig, struct k_sigaction *ka, > siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, >- unsigned long *newspp, unsigned long frame) >+ unsigned long newsp) > { >- struct sigcontext_struct *sc; >- struct rt_sigframe *rt_sf; >- >- if (regs->trap == 0x0C00 /* System Call! */ >- && ((int)regs->result == -ERESTARTNOHAND || >- ((int)regs->result == -ERESTARTSYS && >- !(ka->sa.sa_flags & SA_RESTART)))) >- regs->result = -EINTR; >+ struct sigcontext *sc; >+ struct sigregs *frame; >+ unsigned long origsp = newsp; > > /* Set up Signal Frame */ >- if (ka->sa.sa_flags & SA_SIGINFO) { >- /* Put a Real Time Context onto stack */ >- *newspp -= sizeof(*rt_sf); >- rt_sf = (struct rt_sigframe *) *newspp; >- if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) >- goto badframe; >- >- if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler) >- || __put_user(&rt_sf->info, &rt_sf->pinfo) >- || __put_user(&rt_sf->uc, &rt_sf->puc) >- /* Put the siginfo */ >- || __copy_to_user(&rt_sf->info, info, sizeof(*info)) >- /* Create the ucontext */ >- || __put_user(0, &rt_sf->uc.uc_flags) >- || __put_user(0, &rt_sf->uc.uc_link) >- || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) >- || __put_user(sas_ss_flags(regs->gpr[1]), >- &rt_sf->uc.uc_stack.ss_flags) >- || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) >- || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)) >- /* mcontext.regs points to preamble register frame */ >- || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs) >- || __put_user(sig, &rt_sf->uc.uc_mcontext.signal)) >- goto badframe; >- } else { >- /* Put another sigcontext on the stack */ >- *newspp -= sizeof(*sc); >- sc = (struct sigcontext_struct *) *newspp; >- if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) >- goto badframe; >- >- if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) >- || __put_user(oldset->sig[0], &sc->oldmask) >-#if _NSIG_WORDS > 1 >- || __put_user(oldset->sig[1], &sc->_unused[3]) >+ newsp -= sizeof(struct sigregs); >+ frame = (struct sigregs *) newsp; >+ >+ /* Put a sigcontext on the stack */ >+ newsp -= sizeof(*sc); >+ sc = (struct sigcontext *) newsp; >+ >+ /* create a stack frame for the caller of the handler */ >+ newsp -= __SIGNAL_FRAMESIZE; >+ >+ if (verify_area(VERIFY_WRITE, (void *) newsp, origsp - newsp)) >+ goto badframe; >+ >+#if _NSIG != 64 >+#error "Please adjust handle_signal()" > #endif >- || __put_user((struct pt_regs *)frame, &sc->regs) >- || __put_user(sig, &sc->signal)) >- goto badframe; >- } >+ if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) >+ || __put_user(oldset->sig[0], &sc->oldmask) >+ || __put_user(oldset->sig[1], &sc->_unused[3]) >+ || __put_user((struct pt_regs *)frame, &sc->regs) >+ || __put_user(sig, &sc->signal)) >+ goto badframe; > >- if (ka->sa.sa_flags & SA_ONESHOT) >- ka->sa.sa_handler = SIG_DFL; >+ if (save_user_regs(regs, &frame->mctx, 0x7777, 0)) >+ goto badframe; >+ >+ if (put_user(regs->gpr[1], (unsigned long *)newsp)) >+ goto badframe; >+ regs->gpr[1] = newsp; >+ regs->gpr[3] = sig; >+ regs->gpr[4] = (unsigned long) sc; >+ regs->nip = (unsigned long) ka->sa.sa_handler; >+ regs->link = (unsigned long) frame->mctx.tramp; > >- if (!(ka->sa.sa_flags & SA_NODEFER)) { >- spin_lock_irq(¤t->sigmask_lock); >- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); >- sigaddset(¤t->blocked,sig); >- recalc_sigpending(current); >- spin_unlock_irq(¤t->sigmask_lock); >- } > return; > > badframe: >@@ -547,30 +548,48 @@ > } > > /* >- * Note that 'init' is a special process: it doesn't get signals it doesn't >- * want to handle. Thus you cannot kill init even with a SIGKILL even by >- * mistake. >+ * Do a signal return; undo the signal stack. > */ >-int do_signal(sigset_t *oldset, struct pt_regs *regs) >+int sys_sigreturn(struct pt_regs *regs) > { >- siginfo_t info; >- struct k_sigaction *ka; >- unsigned long frame, newsp; >+ struct sigcontext *sc, sigctx; >+ struct mcontext *sr; >+ int ret; >+ sigset_t set; > >- if (!oldset) >- oldset = ¤t->blocked; >+ sc = (struct sigcontext *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); >+ if (copy_from_user(&sigctx, sc, sizeof(sigctx))) >+ goto badframe; > >- newsp = frame = 0; >+ set.sig[0] = sigctx.oldmask; >+ set.sig[1] = sigctx._unused[3]; >+ restore_sigmask(&set); > >- for (;;) { >- unsigned long signr; >+ sr = (struct mcontext *) sigctx.regs; >+ if (verify_area(VERIFY_READ, sr, sizeof(*sr)) >+ || restore_user_regs(regs, sr, 0)) >+ goto badframe; >+ >+ ret = regs->result; > >+ return ret; >+ >+badframe: >+ do_exit(SIGSEGV); >+} >+ >+static int get_signal_to_deliver(struct siginfo *infop, struct pt_regs *regs) >+{ >+ struct k_sigaction *ka; >+ int signr; >+ >+ for (;;) { > spin_lock_irq(¤t->sigmask_lock); >- signr = dequeue_signal(¤t->blocked, &info); >+ signr = dequeue_signal(¤t->blocked, infop); > spin_unlock_irq(¤t->sigmask_lock); > > if (!signr) >- break; >+ return 0; > > if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { > /* Let the debugger run. */ >@@ -589,17 +608,17 @@ > continue; > > /* Update the siginfo structure. Is this good? */ >- if (signr != info.si_signo) { >- info.si_signo = signr; >- info.si_errno = 0; >- info.si_code = SI_USER; >- info.si_pid = current->p_pptr->pid; >- info.si_uid = current->p_pptr->uid; >+ if (signr != infop->si_signo) { >+ infop->si_signo = signr; >+ infop->si_errno = 0; >+ infop->si_code = SI_USER; >+ infop->si_pid = current->p_pptr->pid; >+ infop->si_uid = current->p_pptr->uid; > } > > /* If the (new) signal is now blocked, requeue it. */ > if (sigismember(¤t->blocked, signr)) { >- send_sig_info(signr, &info, current); >+ send_sig_info(signr, infop, current); > continue; > } > } >@@ -646,39 +665,85 @@ > /* FALLTHRU */ > > default: >- sig_exit(signr, exit_code, &info); >+ sig_exit(signr, exit_code, infop); > /* NOTREACHED */ > } > } >+ return signr; >+ } >+} >+ >+/* >+ * Note that 'init' is a special process: it doesn't get signals it doesn't >+ * want to handle. Thus you cannot kill init even with a SIGKILL even by >+ * mistake. >+ */ >+int do_signal(sigset_t *oldset, struct pt_regs *regs) >+{ >+ siginfo_t info; >+ struct k_sigaction *ka; >+ unsigned long frame, newsp; >+ int signr; >+ >+ if (!oldset) >+ oldset = ¤t->blocked; >+ >+ newsp = frame = 0; > >- if ( (ka->sa.sa_flags & SA_ONSTACK) >- && (! on_sig_stack(regs->gpr[1]))) >- newsp = (current->sas_ss_sp + current->sas_ss_size); >- else >- newsp = regs->gpr[1]; >- newsp = frame = newsp - sizeof(struct sigregs); >- >- /* Whee! Actually deliver the signal. */ >- handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); >- break; >- } >- >- if (regs->trap == 0x0C00 /* System Call! */ && >- ((int)regs->result == -ERESTARTNOHAND || >- (int)regs->result == -ERESTARTSYS || >- (int)regs->result == -ERESTARTNOINTR)) { >- regs->gpr[3] = regs->orig_gpr3; >- regs->nip -= 4; /* Back up & retry system call */ >- regs->result = 0; >+ signr = get_signal_to_deliver(&info, regs); >+ >+ ka = (signr == 0)? NULL: ¤t->sig->action[signr-1]; >+ >+ if (regs->trap == 0xc00) { /* system call */ >+ switch ((int) regs->result) { >+ case -ERESTARTSYS: >+ if (signr == 0 || (ka->sa.sa_flags & SA_RESTART)) >+ goto retry; >+ /* fall through */ >+ case -ERESTARTNOHAND: >+ if (signr > 0) { >+ /* make the system call return an EINTR */ >+ regs->result = -EINTR; >+ break; >+ } >+ /* fall through */ >+ case -ERESTARTNOINTR: >+ retry: >+ /* Back up & retry system call */ >+ regs->gpr[3] = regs->orig_gpr3; >+ regs->nip -= 4; >+ regs->result = 0; >+ break; >+ } > } > >- if (newsp == frame) >+ if (signr == 0) > return 0; /* no signals delivered */ > >+ if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size >+ && !on_sig_stack(regs->gpr[1])) >+ newsp = current->sas_ss_sp + current->sas_ss_size; >+ else >+ newsp = regs->gpr[1]; >+ newsp &= ~0xfUL; >+ >+ /* Whee! Actually deliver the signal. */ > if (ka->sa.sa_flags & SA_SIGINFO) >- setup_rt_frame(regs, (struct sigregs *) frame, newsp); >+ handle_rt_signal(signr, ka, &info, oldset, regs, newsp); > else >- setup_frame(regs, (struct sigregs *) frame, newsp); >+ handle_signal(signr, ka, &info, oldset, regs, newsp); >+ >+ if (ka->sa.sa_flags & SA_ONESHOT) >+ ka->sa.sa_handler = SIG_DFL; >+ >+ if (!(ka->sa.sa_flags & SA_NODEFER)) { >+ spin_lock_irq(¤t->sigmask_lock); >+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); >+ sigaddset(¤t->blocked, signr); >+ recalc_sigpending(current); >+ spin_unlock_irq(¤t->sigmask_lock); >+ } >+ > return 1; > } > >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/smp-tbsync.c linux-2.4.22-ppc-dev/arch/ppc/kernel/smp-tbsync.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/smp-tbsync.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/smp-tbsync.c 2003-08-25 23:37:36.000000000 +0200 >@@ -0,0 +1,182 @@ >+/* >+ * Smp timebase synchronization for ppc. >+ * >+ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) >+ * >+ */ >+ >+#include <linux/config.h> >+#include <linux/kernel.h> >+#include <linux/sched.h> >+#include <linux/smp.h> >+#include <linux/unistd.h> >+#include <linux/init.h> >+#include <linux/slab.h> >+#include <asm/atomic.h> >+#include <asm/smp.h> >+#include <asm/time.h> >+ >+#define NUM_ITER 300 >+ >+enum { >+ kExit=0, kSetAndTest, kTest >+}; >+ >+static struct { >+ volatile int tbu; >+ volatile int tbl; >+ volatile int mark; >+ volatile int cmd; >+ volatile int handshake; >+ int filler[3]; >+ >+ volatile int ack; >+ int filler2[7]; >+ >+ volatile int race_result; >+} *tbsync; >+ >+static volatile int running; >+ >+static void __devinit >+enter_contest( int mark, int add ) >+{ >+ while( (int)(get_tbl() - mark) < 0 ) >+ tbsync->race_result = add; >+} >+ >+void __devinit >+smp_generic_take_timebase( void ) >+{ >+ int cmd, tbl, tbu; >+ >+ local_irq_disable(); >+ while( !running ) >+ ; >+ rmb(); >+ >+ for( ;; ) { >+ tbsync->ack = 1; >+ while( !tbsync->handshake ) >+ ; >+ rmb(); >+ >+ cmd = tbsync->cmd; >+ tbl = tbsync->tbl; >+ tbu = tbsync->tbu; >+ tbsync->ack = 0; >+ if( cmd == kExit ) >+ return; >+ >+ if( cmd == kSetAndTest ) { >+ while( tbsync->handshake ) >+ ; >+ asm volatile ("mttbl %0" :: "r" (tbl) ); >+ asm volatile ("mttbu %0" :: "r" (tbu) ); >+ } else { >+ while( tbsync->handshake ) >+ ; >+ } >+ enter_contest( tbsync->mark, -1 ); >+ } >+ local_irq_enable(); >+} >+ >+static int __devinit >+start_contest( int cmd, int offset, int num ) >+{ >+ int i, tbu, tbl, mark, score=0; >+ >+ tbsync->cmd = cmd; >+ >+ local_irq_disable(); >+ for( i=-3; i<num; ) { >+ tbl = get_tbl() + 400; >+ tbsync->tbu = tbu = get_tbu(); >+ tbsync->tbl = tbl + offset; >+ tbsync->mark = mark = tbl + 400; >+ >+ wmb(); >+ >+ tbsync->handshake = 1; >+ while( tbsync->ack ) >+ ; >+ >+ while( (int)(get_tbl() - tbl) <= 0 ) >+ ; >+ tbsync->handshake = 0; >+ enter_contest( mark, 1 ); >+ >+ while( !tbsync->ack ) >+ ; >+ >+ if( tbsync->tbu != get_tbu() || ((tbsync->tbl ^ get_tbl()) & 0x80000000) ) >+ continue; >+ if( i++ > 0 ) >+ score += tbsync->race_result; >+ } >+ local_irq_enable(); >+ return score; >+} >+ >+void __devinit >+smp_generic_give_timebase( void ) >+{ >+ int i, score, score2, old, min=0, max=5000, offset=1000; >+ >+ printk("Synchronizing timebase\n"); >+ >+ /* if this fails then this kernel won't work anyway... */ >+ tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL ); >+ memset( tbsync, 0, sizeof(*tbsync) ); >+ mb(); >+ running = 1; >+ >+ while( !tbsync->ack ) >+ ; >+ >+ /* binary search */ >+ for( old=-1 ; old != offset ; offset=(min+max)/2 ) { >+ score = start_contest( kSetAndTest, offset, NUM_ITER ); >+ >+ printk("score %d, offset %d\n", score, offset ); >+ >+ if( score > 0 ) >+ max = offset; >+ else >+ min = offset; >+ old = offset; >+ } >+ score = start_contest( kSetAndTest, min, NUM_ITER ); >+ score2 = start_contest( kSetAndTest, max, NUM_ITER ); >+ >+ printk( "Min %d (score %d), Max %d (score %d)\n", min, score, max, score2 ); >+ score = abs( score ); >+ score2 = abs( score2 ); >+ offset = (score < score2) ? min : max; >+ >+ /* guard against inaccurate mttb */ >+ for( i=0; i<10; i++ ) { >+ start_contest( kSetAndTest, offset, NUM_ITER/10 ); >+ >+ if( (score2=start_contest(kTest, offset, NUM_ITER)) < 0 ) >+ score2 = -score2; >+ if( score2 <= score || score2 < 20 ) >+ break; >+ } >+ printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER ); >+ >+ /* exiting */ >+ tbsync->cmd = kExit; >+ wmb(); >+ tbsync->handshake = 1; >+ while( tbsync->ack ) >+ ; >+ tbsync->handshake = 0; >+ kfree( tbsync ); >+ tbsync = NULL; >+ running = 0; >+ >+ /* all done */ >+ smp_tb_synchronized = 1; >+} >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/smp.c linux-2.4.22-ppc-dev/arch/ppc/kernel/smp.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/smp.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/smp.c 2003-08-25 23:37:50.000000000 +0200 >@@ -55,14 +55,13 @@ > /* all cpu mappings are 1-1 -- Cort */ > volatile unsigned long cpu_callin_map[NR_CPUS]; > >-#define TB_SYNC_PASSES 4 >-volatile unsigned long __initdata tb_sync_flag = 0; >-volatile unsigned long __initdata tb_offset = 0; >- > int start_secondary(void *); > extern int cpu_idle(void *unused); > void smp_call_function_interrupt(void); > >+extern void smp_generic_take_timebase(void); >+extern void smp_generic_give_timebase(void); >+ > /* Low level assembly function used to backup CPU 0 state */ > extern void __save_cpu_setup(void); > >@@ -230,6 +229,10 @@ > timeout = 1000000; > while (atomic_read(&data.started) != cpus) { > if (--timeout == 0) { >+#ifdef CONFIG_XMON >+ xmon_printf("smp_call_function on cpu %d: other cpus not responding (%d)\n", >+ smp_processor_id(), atomic_read(&data.started)); >+#endif > printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", > smp_processor_id(), atomic_read(&data.started)); > goto out; >@@ -242,6 +245,10 @@ > timeout = 1000000; > while (atomic_read(&data.finished) != cpus) { > if (--timeout == 0) { >+#ifdef CONFIG_XMON >+ xmon_printf("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", >+ smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); >+#endif > printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", > smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); > goto out; >@@ -399,81 +406,6 @@ > smp_tb_synchronized = 1; > } > >-void __init smp_software_tb_sync(int cpu) >-{ >-#define PASSES 4 /* 4 passes.. */ >- int pass; >- int i, j; >- >- /* stop - start will be the number of timebase ticks it takes for cpu0 >- * to send a message to all others and the first reponse to show up. >- * >- * ASSUMPTION: this time is similiar for all cpus >- * ASSUMPTION: the time to send a one-way message is ping/2 >- */ >- register unsigned long start = 0; >- register unsigned long stop = 0; >- register unsigned long temp = 0; >- >- set_tb(0, 0); >- >- /* multiple passes to get in l1 cache.. */ >- for (pass = 2; pass < 2+PASSES; pass++){ >- if (cpu == 0){ >- mb(); >- for (i = j = 1; i < smp_num_cpus; i++, j++){ >- /* skip stuck cpus */ >- while (!cpu_callin_map[j]) >- ++j; >- while (cpu_callin_map[j] != pass) >- barrier(); >- } >- mb(); >- tb_sync_flag = pass; >- start = get_tbl(); /* start timing */ >- while (tb_sync_flag) >- mb(); >- stop = get_tbl(); /* end timing */ >- /* theoretically, the divisor should be 2, but >- * I get better results on my dual mtx. someone >- * please report results on other smp machines.. >- */ >- tb_offset = (stop-start)/4; >- mb(); >- tb_sync_flag = pass; >- udelay(10); >- mb(); >- tb_sync_flag = 0; >- mb(); >- set_tb(0,0); >- mb(); >- } else { >- cpu_callin_map[cpu] = pass; >- mb(); >- while (!tb_sync_flag) >- mb(); /* wait for cpu0 */ >- mb(); >- tb_sync_flag = 0; /* send response for timing */ >- mb(); >- while (!tb_sync_flag) >- mb(); >- temp = tb_offset; /* make sure offset is loaded */ >- while (tb_sync_flag) >- mb(); >- set_tb(0,temp); /* now, set the timebase */ >- mb(); >- } >- } >- if (cpu == 0) { >- smp_tb_synchronized = 1; >- printk("smp_software_tb_sync: %d passes, final offset: %ld\n", >- PASSES, tb_offset); >- } >- /* so time.c doesn't get confused */ >- set_dec(tb_ticks_per_jiffy); >- last_jiffy_stamp(cpu) = 0; >-} >- > void __init smp_commence(void) > { > /* >@@ -486,19 +418,13 @@ > /* if the smp_ops->setup_cpu function has not already synched the > * timebases with a nicer hardware-based method, do so now > * >- * I am open to suggestions for improvements to this method >- * -- Troy <hozer@drgw.net> >- * >- * NOTE: if you are debugging, set smp_tb_synchronized for now >- * since if this code runs pretty early and needs all cpus that >- * reported in in smp_callin_map to be working >- * >- * NOTE2: this code doesn't seem to work on > 2 cpus. -- paulus/BenH >+ * New version backported from Samuel Rydth 2.6 version, unlike 2.6 >+ * version works only for 2 CPUs (easy hack) > */ > if (!smp_tb_synchronized && smp_num_cpus == 2) { > unsigned long flags; > __save_and_cli(flags); >- smp_software_tb_sync(0); >+ smp_generic_give_timebase(); > __restore_flags(flags); > } > } >@@ -518,9 +444,8 @@ > barrier(); > > /* see smp_commence for more info */ >- if (!smp_tb_synchronized && smp_num_cpus == 2) { >- smp_software_tb_sync(cpu); >- } >+ if (!smp_tb_synchronized && smp_num_cpus == 2) >+ smp_generic_take_timebase(); > __sti(); > } > >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/traps.c linux-2.4.22-ppc-dev/arch/ppc/kernel/traps.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/kernel/traps.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/kernel/traps.c 2003-08-25 23:37:40.000000000 +0200 >@@ -85,14 +85,25 @@ > > void die(const char * str, struct pt_regs * fp, long err) > { >+#ifdef CONFIG_BOOTX_TEXT >+ extern int force_printk_to_btext; >+#endif > console_verbose(); > spin_lock_irq(&die_lock); >+#ifdef CONFIG_BOOTX_TEXT >+ force_printk_to_btext = 1; >+#endif > #ifdef CONFIG_PMAC_BACKLIGHT >- set_backlight_enable(1); >- set_backlight_level(BACKLIGHT_MAX); >-#endif >+ if (_machine == _MACH_Pmac) { >+ set_backlight_enable(1); >+ set_backlight_level(BACKLIGHT_MAX); >+ } >+#endif > printk("Oops: %s, sig: %ld\n", str, err); > show_regs(fp); >+#ifdef CONFIG_BOOTX_TEXT >+ force_printk_to_btext = 0; >+#endif > spin_unlock_irq(&die_lock); > /* do_exit() should take care of panic'ing from an interrupt > * context so we don't handle it here >@@ -153,9 +164,11 @@ > > --nip; > rb = (*nip >> 11) & 0x1f; >+#if 0 > printk(KERN_DEBUG "%s bad port %lx at %p\n", > (*nip & 0x100)? "OUT to": "IN from", > regs->gpr[rb] - _IO_BASE, nip); >+#endif > regs->nip = fixup; > return 1; > } >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/lib/locks.c linux-2.4.22-ppc-dev/arch/ppc/lib/locks.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/lib/locks.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/lib/locks.c 2003-08-25 23:37:25.000000000 +0200 >@@ -15,6 +15,14 @@ > > #if SPINLOCK_DEBUG > >+/* Route debug output to xmon when possible, there are more chances >+ * for it to work than the console >+ */ >+#ifdef CONFIG_XMON >+extern void xmon_printf(const char* fmt,...); >+#define printk xmon_printf >+#endif >+ > #undef INIT_STUCK > #define INIT_STUCK 200000000 /*0xffffffff*/ > >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/mm/fault.c linux-2.4.22-ppc-dev/arch/ppc/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/mm/fault.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/mm/fault.c 2003-08-25 23:37:55.000000000 +0200 >@@ -96,7 +96,7 @@ > void do_page_fault(struct pt_regs *regs, unsigned long address, > unsigned long error_code) > { >- struct vm_area_struct * vma; >+ struct vm_area_struct * vma, * prev_vma; > struct mm_struct *mm = current->mm; > siginfo_t info; > int code = SEGV_MAPERR; >@@ -177,7 +177,8 @@ > && (!user_mode(regs) || !store_updates_sp(regs))) > goto bad_area; > } >- if (expand_stack(vma, address)) >+ vma = find_vma_prev(mm, address, &prev_vma); >+ if (expand_stack(vma, address, prev_vma)) > goto bad_area; > > good_area: >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/mm/init.c linux-2.4.22-ppc-dev/arch/ppc/mm/init.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/mm/init.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/mm/init.c 2003-08-25 23:37:27.000000000 +0200 >@@ -457,6 +457,17 @@ > high_memory = (void *) __va(PPC_MEMSTART + total_lowmem); > num_physpages = max_mapnr; /* RAM is assumed contiguous */ > >+ /* Sanity check: did ioremap_bot stomp over vmalloc space ? We keep >+ * a minimal 16Mb guard though if you only have 16Mb left, you'll >+ * probably run into trouble, so we also printk something if you >+ * have less than 64Mb. This is meant to help diagnosing such problems >+ * as debugging it can be really painful. --BenH. >+ */ >+ if (VMALLOC_END < (VMALLOC_START + 0x01000000UL)) >+ panic("Argh ! Virtual space exhausted !"); >+ if (VMALLOC_END < (VMALLOC_START + 0x04000000UL)) >+ printk(KERN_WARNING "Warning ! Virtual space small !"); >+ > totalram_pages += free_all_bootmem(); > > #ifdef CONFIG_BLK_DEV_INITRD >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/mm/pgtable.c linux-2.4.22-ppc-dev/arch/ppc/mm/pgtable.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/mm/pgtable.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/mm/pgtable.c 2003-08-25 23:37:44.000000000 +0200 >@@ -238,7 +238,7 @@ > > printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb," > " residual: %ldMb\n", __bat2 >> 20, __bat3 >> 20, >- (total_lowmem - (__bat2 - __bat3)) >> 20); >+ (total_memory - (__bat2 - __bat3)) >> 20); > > /* On SMP, we limit the lowmem to the area mapped with BATs. > * We also assume nobody will do SMP with 601s >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/Makefile linux-2.4.22-ppc-dev/arch/ppc/platforms/Makefile >--- linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/Makefile 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/platforms/Makefile 2003-08-25 23:37:40.000000000 +0200 >@@ -41,6 +41,9 @@ > prep_time.o prep_setup.o pmac_sleep.o \ > pmac_nvram.o > obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o >+ifeq ($(CONFIG_ALL_PPC),y) >+obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o >+endif > obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o > obj-$(CONFIG_PREP_RESIDUAL) += residual.o > obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/pmac_cpufreq.c linux-2.4.22-ppc-dev/arch/ppc/platforms/pmac_cpufreq.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/pmac_cpufreq.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/ppc/platforms/pmac_cpufreq.c 2003-08-25 23:37:54.000000000 +0200 >@@ -0,0 +1,352 @@ >+#include <linux/config.h> >+#include <linux/types.h> >+#include <linux/errno.h> >+#include <linux/kernel.h> >+#include <linux/delay.h> >+#include <linux/sched.h> >+#include <linux/adb.h> >+#include <linux/pmu.h> >+#include <linux/slab.h> >+#include <linux/cpufreq.h> >+#include <linux/init.h> >+#include <asm/prom.h> >+#include <asm/machdep.h> >+#include <asm/irq.h> >+#include <asm/hardirq.h> >+#include <asm/pmac_feature.h> >+#include <asm/mmu_context.h> >+#include <asm/sections.h> >+#include <asm/cputable.h> >+#include <asm/time.h> >+ >+#undef DEBUG_FREQ >+ >+extern void low_choose_750fx_pll(int pll); >+extern void low_sleep_handler(void); >+extern void openpic_sleep_save_intrs(void); >+extern void openpic_sleep_restore_intrs(void); >+extern void enable_kernel_altivec(void); >+extern void enable_kernel_fp(void); >+ >+static unsigned int low_freq; >+static unsigned int hi_freq; >+static unsigned int cur_freq; >+static int cpufreq_uses_pmu; >+ >+#define PMAC_CPU_LOW_SPEED 1 >+#define PMAC_CPU_HIGH_SPEED 0 >+ >+static inline void >+wakeup_decrementer(void) >+{ >+ set_dec(tb_ticks_per_jiffy); >+ /* No currently-supported powerbook has a 601, >+ * so use get_tbl, not native >+ */ >+ last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); >+} >+ >+#ifdef DEBUG_FREQ >+static inline void >+debug_calc_bogomips(void) >+{ >+ /* This will cause a recalc of bogomips and display the >+ * result. We backup/restore the value to avoid affecting the >+ * core cpufreq framework's own calculation. >+ */ >+ extern void calibrate_delay(void); >+ >+ unsigned long save_lpj = loops_per_jiffy; >+ calibrate_delay(); >+ loops_per_jiffy = save_lpj; >+} >+#endif >+ >+/* Switch CPU speed under 750FX CPU control >+ */ >+static int __pmac >+cpu_750fx_cpu_speed(int low_speed) >+{ >+#ifdef DEBUG_FREQ >+ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); >+#endif >+ low_choose_750fx_pll(low_speed); >+#ifdef DEBUG_FREQ >+ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); >+ debug_calc_bogomips(); >+#endif >+ >+ return 0; >+} >+ >+/* Switch CPU speed under PMU control >+ */ >+static int __pmac >+pmu_set_cpu_speed(unsigned int low_speed) >+{ >+ struct adb_request req; >+ unsigned long save_l2cr; >+ unsigned long save_l3cr; >+ >+#ifdef DEBUG_FREQ >+ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); >+#endif >+ /* Disable all interrupt sources on openpic */ >+ openpic_sleep_save_intrs(); >+ >+ /* Make sure the PMU is idle */ >+ pmu_suspend(); >+ >+ /* Make sure the decrementer won't interrupt us */ >+ asm volatile("mtdec %0" : : "r" (0x7fffffff)); >+ /* Make sure any pending DEC interrupt occuring while we did >+ * the above didn't re-enable the DEC */ >+ mb(); >+ asm volatile("mtdec %0" : : "r" (0x7fffffff)); >+ >+ /* We can now disable MSR_EE */ >+ local_irq_disable(); >+ >+ /* Giveup the FPU & vec */ >+ enable_kernel_fp(); >+ >+#ifdef CONFIG_ALTIVEC >+ if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) >+ enable_kernel_altivec(); >+#endif /* CONFIG_ALTIVEC */ >+ >+ /* Save & disable L2 and L3 caches */ >+ save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ >+ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ >+ if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) >+ _set_L3CR(save_l3cr & 0x7fffffff); >+ if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) >+ _set_L2CR(save_l2cr & 0x7fffffff); >+ >+ /* Send the new speed command. My assumption is that this command >+ * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep >+ */ >+ pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed); >+ while (!req.complete) >+ pmu_poll(); >+ >+ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1); >+ >+ low_sleep_handler(); >+ >+ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0); >+ >+ /* Restore L2 cache */ >+ if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) >+ _set_L2CR(save_l2cr); >+ /* Restore L3 cache */ >+ if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) >+ _set_L3CR(save_l3cr); >+ >+ /* Restore userland MMU context */ >+ set_context(current->active_mm->context, current->active_mm->pgd); >+ >+ pmu_unlock(); >+ >+#ifdef DEBUG_FREQ >+ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); >+#endif >+ >+ /* Restore decrementer */ >+ wakeup_decrementer(); >+ >+ /* Restore interrupts */ >+ openpic_sleep_restore_intrs(); >+ >+ pmu_resume(); >+ >+ /* Let interrupts flow again ... */ >+ local_irq_enable(); >+ >+#ifdef DEBUG_FREQ >+ debug_calc_bogomips(); >+#endif >+ >+ return 0; >+} >+ >+static int __pmac >+do_set_cpu_speed(int speed_mode) >+{ >+ struct cpufreq_freqs freqs; >+ int rc; >+ >+ freqs.old = cur_freq; >+ freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; >+ freqs.cpu = CPUFREQ_ALL_CPUS; >+ >+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); >+ if (cpufreq_uses_pmu) >+ rc = pmu_set_cpu_speed(speed_mode); >+ else >+ rc = cpu_750fx_cpu_speed(speed_mode); >+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); >+ cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; >+ >+ return rc; >+} >+ >+static int __pmac >+pmac_cpufreq_verify(struct cpufreq_policy *policy) >+{ >+ if (!policy) >+ return -EINVAL; >+ >+ policy->cpu = 0; /* UP only */ >+ >+ cpufreq_verify_within_limits(policy, low_freq, hi_freq); >+ >+ if ((policy->min > low_freq) && >+ (policy->max < hi_freq)) >+ policy->max = hi_freq; >+ >+ return 0; >+} >+ >+static int __pmac >+pmac_cpufreq_setpolicy(struct cpufreq_policy *policy) >+{ >+ int rc; >+ >+ if (!policy) >+ return -EINVAL; >+ if (policy->min > low_freq) >+ rc = do_set_cpu_speed(PMAC_CPU_HIGH_SPEED); >+ else if (policy->max < hi_freq) >+ rc = do_set_cpu_speed(PMAC_CPU_LOW_SPEED); >+ else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) >+ rc = do_set_cpu_speed(PMAC_CPU_LOW_SPEED); >+ else >+ rc = do_set_cpu_speed(PMAC_CPU_HIGH_SPEED); >+ >+ return rc; >+} >+ >+unsigned int __pmac >+pmac_get_cur_cpufreq(void) >+{ >+ return cur_freq; >+} >+ >+ >+/* Currently, we support the following machines: >+ * >+ * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) >+ * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) >+ * - iBook2 500 (PMU based, 400Mhz & 500Mhz) >+ * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) >+ */ >+static int __init >+pmac_cpufreq_setup(void) >+{ >+ struct device_node *cpunode; >+ struct cpufreq_driver *driver; >+ u32 *value; >+ int has_freq_ctl = 0; >+ int rc; >+ >+ memset(&driver, 0, sizeof(driver)); >+ >+ /* Assume only one CPU */ >+ cpunode = find_type_devices("cpu"); >+ if (!cpunode) >+ goto out; >+ >+ /* Get current cpu clock freq */ >+ value = (u32 *)get_property(cpunode, "clock-frequency", NULL); >+ if (!value) >+ goto out; >+ cur_freq = (*value) / 1000; >+ >+ /* Check for newer machines */ >+ if (machine_is_compatible("PowerBook3,4") || >+ machine_is_compatible("PowerBook3,5") || >+ machine_is_compatible("MacRISC3")) { >+ value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); >+ if (!value) >+ goto out; >+ low_freq = (*value) / 1000; >+ /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree >+ * here */ >+ if (low_freq < 100000) >+ low_freq *= 10; >+ >+ value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); >+ if (!value) >+ goto out; >+ hi_freq = (*value) / 1000; >+ has_freq_ctl = 1; >+ cpufreq_uses_pmu = 1; >+ } >+ /* Else check for iBook2 500 */ >+ else if (machine_is_compatible("PowerBook4,1")) { >+ /* We only know about 500Mhz model */ >+ if (cur_freq < 450000 || cur_freq > 550000) >+ goto out; >+ hi_freq = cur_freq; >+ low_freq = 400000; >+ has_freq_ctl = 1; >+ cpufreq_uses_pmu = 1; >+ } >+ /* Else check for TiPb 500 */ >+ else if (machine_is_compatible("PowerBook3,2")) { >+ /* We only know about 500Mhz model */ >+ if (cur_freq < 450000 || cur_freq > 550000) >+ goto out; >+ hi_freq = cur_freq; >+ low_freq = 300000; >+ has_freq_ctl = 1; >+ cpufreq_uses_pmu = 1; >+ } >+ /* Else check for 750FX */ >+ else if (PVR_VER(mfspr(PVR)) == 0x7000) { >+ if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) >+ goto out; >+ hi_freq = cur_freq; >+ value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); >+ if (!value) >+ goto out; >+ low_freq = (*value) / 1000; >+ cpufreq_uses_pmu = 0; >+ has_freq_ctl = 1; >+ } >+out: >+ if (!has_freq_ctl) >+ return -ENODEV; >+ >+ /* initialization of main "cpufreq" code*/ >+ driver = kmalloc(sizeof(struct cpufreq_driver) + >+ NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); >+ if (!driver) >+ return -ENOMEM; >+ >+ driver->policy = (struct cpufreq_policy *) (driver + 1); >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+ driver->cpu_min_freq[0] = low_freq; >+ driver->cpu_cur_freq[0] = cur_freq; >+#endif >+ >+ driver->verify = &pmac_cpufreq_verify; >+ driver->setpolicy = &pmac_cpufreq_setpolicy; >+ >+ driver->policy[0].cpu = 0; >+ driver->policy[0].min = low_freq; >+ driver->policy[0].max = cur_freq; >+ driver->policy[0].max_cpu_freq = hi_freq; >+ driver->policy[0].policy = (cur_freq == low_freq) ? >+ CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; >+ >+ rc = cpufreq_register(driver); >+ if (rc) >+ kfree(driver); >+ return rc; >+} >+ >+__initcall(pmac_cpufreq_setup); >+ >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/pmac_setup.c linux-2.4.22-ppc-dev/arch/ppc/platforms/pmac_setup.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/pmac_setup.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/platforms/pmac_setup.c 2003-08-25 23:37:28.000000000 +0200 >@@ -50,6 +50,7 @@ > #include <linux/seq_file.h> > #include <linux/blkdev.h> > #include <linux/genhd.h> >+#include <linux/cpufreq.h> > > #include <asm/processor.h> > #include <asm/sections.h> >@@ -150,7 +151,15 @@ > { > struct device_node *cpu_node; > int *fp, s; >- >+ >+#ifdef CONFIG_CPU_FREQ_PMAC >+ extern unsigned int pmac_get_cur_cpufreq(void); >+ unsigned int freq = pmac_get_cur_cpufreq(); >+ if (freq != 0) { >+ seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); >+ return 0; >+ } >+#endif /* CONFIG_CPU_FREQ_PMAC */ > cpu_node = find_type_devices("cpu"); > if (!cpu_node) > return 0; >@@ -197,12 +206,27 @@ > } > seq_printf(m, "\n"); > } >+ pp = (char *) get_property(np, "scb#", &plen); >+ if (pp != NULL) >+ seq_printf(m, "board revision\t: %08x\n", *((int *)pp)); > } else > seq_printf(m, "PowerMac\n"); > > /* print parsed model */ > seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); > seq_printf(m, "pmac flags\t: %08x\n", mbflags); >+#if 0 >+{ >+ extern long nap_return_count; >+ extern long nap_enter_count; >+ extern long nap_save_msscr0; >+ extern long dbg_nap_ret; >+ seq_printf(m, "nap_return_count: %d\n", nap_return_count); >+ seq_printf(m, "nap_enter_count\t: %d\n", nap_enter_count); >+ seq_printf(m, "nap_save_msscr0\t: %x\n", nap_save_msscr0); >+ seq_printf(m, "dbg_nap_ret\t: %x\n", dbg_nap_ret); >+} >+#endif > > /* find l2 cache info */ > np = find_devices("l2-cache"); >@@ -309,6 +333,14 @@ > sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); > ohare_init(); > >+ /* Check & display some CPU config registers for diagnostic */ >+ if (pvr == 0x8000 || pvr == 0x8001) { /* 745x */ >+ printk(KERN_INFO "CPU MSCCR0 : 0x%08x\n", mfspr(SPRN_MSSCR0)); >+ printk(KERN_INFO "CPU HID1 : 0x%08x\n", mfspr(SPRN_HID1)); >+ } >+ if (pvr == 0x0008 || pvr == 0x7000) /* 750's */ >+ printk(KERN_INFO "CPU HID1 : 0x%08x\n", mfspr(SPRN_HID1)); >+ > /* Lookup PCI hosts */ > pmac_find_bridges(); > >@@ -329,6 +361,9 @@ > } > } > >+#if 0 >+ printk("MSSCR0: %x\n", mfspr(SPRN_MSSCR0)); >+#endif > if (ppc_override_l2cr) > printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n", > ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) >@@ -823,6 +858,12 @@ > #endif /* CONFIG_VT */ > } > >+static int __pmac >+pmac_ide_reserved_hwifs(void) >+{ >+ return 0; >+} >+ > void __init > pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, > unsigned long r6, unsigned long r7) >@@ -864,6 +905,7 @@ > select_adb_keyboard(); > > #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) >+ ppc_ide_md.reserved_hwifs = pmac_ide_reserved_hwifs; > #ifdef CONFIG_BLK_DEV_IDE_PMAC > ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; > ppc_ide_md.default_io_base = pmac_ide_get_base; >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/pmac_sleep.S linux-2.4.22-ppc-dev/arch/ppc/platforms/pmac_sleep.S >--- linux-2.4.22-ppc-dev.orig/arch/ppc/platforms/pmac_sleep.S 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/platforms/pmac_sleep.S 2003-08-25 23:37:26.000000000 +0200 >@@ -44,7 +44,7 @@ > .text > .align 5 > >-#if defined(CONFIG_PMAC_PBOOK) >+#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC) > > /* This gets called by via-pmu.c late during the sleep process. > * The PMU was already send the sleep command and will shut us down >@@ -372,7 +372,7 @@ > isync > rfi > >-#endif /* defined(CONFIG_PMAC_PBOOK) */ >+#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */ > > .data > .balign L1_CACHE_LINE_SIZE >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/xmon/start.c linux-2.4.22-ppc-dev/arch/ppc/xmon/start.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/xmon/start.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/xmon/start.c 2003-08-25 23:37:28.000000000 +0200 >@@ -12,6 +12,7 @@ > #include <linux/kernel.h> > #include <linux/errno.h> > #include <linux/sysrq.h> >+#include <linux/delay.h> > #include <asm/prom.h> > #include <asm/bootx.h> > #include <asm/machdep.h> >@@ -24,16 +25,34 @@ > #include <asm/bitops.h> > #endif > >+#define CONFIG_XMON_FW >+ > static volatile unsigned char *sccc, *sccd; > unsigned int TXRDY, RXRDY, DLAB; > extern void xmon_printf(const char *fmt, ...); > static int xmon_expect(const char *str, unsigned int timeout); >+extern char cmd_line[512]; > > static int use_screen; > static int via_modem; > static int xmon_use_sccb; > static struct device_node *channel_node; > >+/* There are used when hooked via firewire */ >+#ifdef CONFIG_XMON_FW >+volatile unsigned int xmon_fw_outbuf_size; >+volatile unsigned char xmon_fw_outbuf[1024]; >+volatile unsigned int xmon_fw_oflags; >+volatile unsigned int xmon_fw_iflags; >+volatile unsigned int xmon_fw_idata; >+#define XMON_FW_FLAGS_OUT_ENTERED 0x00000001 >+#define XMON_FW_FLAGS_OUT_DATA 0x00000002 >+#define XMON_FW_FLAGS_OUT_ACK 0x00000004 >+#define XMON_FW_FLAGS_IN_ATTACHED 0x00000001 >+#define XMON_FW_FLAGS_IN_DATA 0x00000002 >+#define XMON_FW_FLAGS_IN_ACK 0x00000004 >+#endif >+ > #define TB_SPEED 25000000 > > static inline unsigned int readtb(void) >@@ -112,7 +131,9 @@ > volatile unsigned char *base; > > use_screen = 0; >- >+ /* Typically used for firewire debugging */ >+ if (strstr(cmd_line, "xmon_noio")) >+ return; > if (_machine == _MACH_Pmac) { > struct device_node *np; > unsigned long addr; >@@ -215,20 +236,21 @@ > DLAB = 0x80; > #endif /* platform */ > >+#ifdef CONFIG_MAGIC_SYSRQ > __sysrq_put_key_op('x', &sysrq_xmon_op); >+#endif > } > > static int scc_initialized = 0; > > void xmon_init_scc(void); >-extern void pmu_poll(void); > extern void cuda_poll(void); > > static inline void do_poll_adb(void) > { > #ifdef CONFIG_ADB_PMU > if (sys_ctrler == SYS_CTRLER_PMU) >- pmu_poll(); >+ pmu_poll_adb(); > #endif /* CONFIG_ADB_PMU */ > #ifdef CONFIG_ADB_CUDA > if (sys_ctrler == SYS_CTRLER_CUDA) >@@ -236,6 +258,114 @@ > #endif /* CONFIG_ADB_CUDA */ > } > >+#if 0 >+static void >+bx_printf(const char* fmt, ...) >+{ >+ static char dbgbuf[2048]; >+ va_list ap; >+ int n; >+ >+ va_start(ap, fmt); >+ n = vsprintf(dbgbuf, fmt, ap); >+ va_end(ap); >+ btext_drawstring(dbgbuf); >+} >+#endif >+ >+#ifdef CONFIG_XMON_FW >+static int >+xmon_fw_write(void* ptr, int nb) >+{ >+ char* p = (char *)ptr; >+ int c, i; >+ >+ while (nb && (xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED)) { >+ c = (nb > 1024) ? 1024 : nb; >+ memcpy((void *)xmon_fw_outbuf, p, c); >+ xmon_fw_outbuf_size = c; >+ wmb(); >+ xmon_fw_oflags |= XMON_FW_FLAGS_OUT_DATA; >+ wmb(); >+ for (i=0; i<1000; i++) { >+ rmb(); >+ if (xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) >+ break; >+ mdelay(1); >+ } >+ xmon_fw_oflags &= ~XMON_FW_FLAGS_OUT_DATA; >+ wmb(); >+ if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) == 0) { >+ xmon_fw_iflags = 0; >+ break; >+ } >+ for (i=0; i<1000; i++) { >+ rmb(); >+ if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) == 0) >+ break; >+ mdelay(1); >+ } >+ if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_ACK) != 0) { >+ xmon_fw_iflags = 0; >+ break; >+ } >+ nb -= c; >+ p += c; >+ } >+ return (xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED) != 0; >+} >+ >+static int >+xmon_fw_read(void* ptr, int nb) >+{ >+ int t, on, i; >+ unsigned int k; >+ char c[3]; >+ char* p = (char *)ptr; >+ >+ while (nb) { >+ t = 0; >+ on = 0; >+ while(xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED) { >+ if (xmon_fw_iflags & XMON_FW_FLAGS_IN_DATA) >+ break; >+ if (--t < 0) { >+ on = 1 - on; >+ c[0] = on? 0xdb: 0x20; >+ c[1] = '\b'; >+ if (!xmon_fw_write(c, 2)) >+ break; >+ t = 2000000; >+ } >+ rmb(); >+ } >+ k = xmon_fw_idata & 0xff; >+ xmon_fw_oflags |= XMON_FW_FLAGS_OUT_ACK; >+ wmb(); >+ for (i=0; i<1000; i++) { >+ rmb(); >+ if ((xmon_fw_iflags & XMON_FW_FLAGS_IN_DATA) == 0) >+ break; >+ mdelay(1); >+ } >+ if (xmon_fw_iflags & XMON_FW_FLAGS_IN_DATA) { >+ xmon_fw_iflags = 0; >+ break; >+ } >+ xmon_fw_oflags &= ~XMON_FW_FLAGS_OUT_ACK; >+ wmb(); >+ if (on) { >+ c[0] = 0x20; c[1] = '\b'; >+ xmon_fw_write(c, 2); >+ } >+ *(p++) = k; >+ nb--; >+ } >+ return (xmon_fw_iflags & XMON_FW_FLAGS_IN_ATTACHED) != 0; >+} >+ >+#endif /* CONFIG_XMON_FW */ >+ > int > xmon_write(void *handle, void *ptr, int nb) > { >@@ -251,9 +381,17 @@ > if (--lock_wait == 0) > break; > #endif >- >+#ifdef CONFIG_XMON_FW >+ if (xmon_fw_write(ptr, nb)) >+ goto out; >+#endif /* CONFIG_XMON_FW */ > #ifdef CONFIG_BOOTX_TEXT >- if (use_screen) { >+#ifdef CONFIG_MORE_DEBUG >+ if (1) >+#else >+ if (use_screen) >+#endif >+ { > /* write it on the screen */ > for (i = 0; i < nb; ++i) > btext_drawchar(*p++); >@@ -262,6 +400,9 @@ > #endif > if (!scc_initialized) > xmon_init_scc(); >+ if (!sccd) >+ goto out; >+ > ct = 0; > for (i = 0; i < nb; ++i) { > while ((*sccc & TXRDY) == 0) >@@ -354,6 +495,10 @@ > char *p = ptr; > int i; > >+#ifdef CONFIG_XMON_FW >+ if (xmon_fw_read(ptr, nb)) >+ return nb; >+#endif /* CONFIG_XMON_FW */ > #ifdef CONFIG_BOOTX_TEXT > if (use_screen) { > for (i = 0; i < nb; ++i) >@@ -363,6 +508,8 @@ > #endif > if (!scc_initialized) > xmon_init_scc(); >+ if (sccd == NULL) >+ return 0; > for (i = 0; i < nb; ++i) { > while ((*sccc & RXRDY) == 0) > do_poll_adb(); >@@ -385,7 +532,8 @@ > > static unsigned char scc_inittab[] = { > 13, 0, /* set baud rate divisor */ >- 12, 1, >+// 12, 1, >+ 12, 0, > 14, 1, /* baud rate gen enable, src=rtxc */ > 11, 0x50, /* clocks = br gen */ > 5, 0xea, /* tx 8 bits, assert DTR & RTS */ >@@ -396,6 +544,8 @@ > void > xmon_init_scc() > { >+ if (sccd == NULL && channel_node == NULL) >+ return; > if ( _machine == _MACH_chrp ) > { > sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ >@@ -634,11 +784,19 @@ > pmu_suspend(); > } > #endif >+#ifdef CONFIG_XMON_FW >+ xmon_fw_oflags |= XMON_FW_FLAGS_OUT_ENTERED; >+ wmb(); >+#endif /* CONFIG_XMON_FW */ > } > > void > xmon_leave(void) > { >+#ifdef CONFIG_XMON_FW >+ xmon_fw_oflags &= ~XMON_FW_FLAGS_OUT_ENTERED; >+ wmb(); >+#endif /* CONFIG_XMON_FW */ > #ifdef CONFIG_ADB_PMU > if (_machine == _MACH_Pmac) { > pmu_resume(); >diff -Naur linux-2.4.22-ppc-dev.orig/arch/ppc/xmon/xmon.c linux-2.4.22-ppc-dev/arch/ppc/xmon/xmon.c >--- linux-2.4.22-ppc-dev.orig/arch/ppc/xmon/xmon.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/ppc/xmon/xmon.c 2003-08-25 23:37:48.000000000 +0200 >@@ -209,14 +209,16 @@ > #endif /* CONFIG_SMP */ > remove_bpts(); > #ifdef CONFIG_PMAC_BACKLIGHT >- if( setjmp(bus_error_jmp) == 0 ) { >- debugger_fault_handler = handle_fault; >- sync(); >- set_backlight_enable(1); >- set_backlight_level(BACKLIGHT_MAX); >- sync(); >+ if (_machine == _MACH_Pmac) { >+ if( setjmp(bus_error_jmp) == 0 ) { >+ debugger_fault_handler = handle_fault; >+ sync(); >+ set_backlight_enable(1); >+ set_backlight_level(BACKLIGHT_MAX); >+ sync(); >+ } >+ debugger_fault_handler = 0; > } >- debugger_fault_handler = 0; > #endif /* CONFIG_PMAC_BACKLIGHT */ > cmd = cmds(excp); > if (cmd == 's') { >diff -Naur linux-2.4.22-ppc-dev.orig/arch/s390/mm/fault.c linux-2.4.22-ppc-dev/arch/s390/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/s390/mm/fault.c 2002-11-29 00:53:11.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/s390/mm/fault.c 2003-08-25 23:37:30.000000000 +0200 >@@ -210,7 +210,7 @@ > goto good_area; > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/s390x/mm/fault.c linux-2.4.22-ppc-dev/arch/s390x/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/s390x/mm/fault.c 2002-11-29 00:53:11.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/s390x/mm/fault.c 2003-08-25 23:37:27.000000000 +0200 >@@ -210,7 +210,7 @@ > goto good_area; > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/sh/mm/fault.c linux-2.4.22-ppc-dev/arch/sh/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/sh/mm/fault.c 2003-08-27 15:17:47.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/sh/mm/fault.c 2003-08-25 23:37:52.000000000 +0200 >@@ -78,7 +78,7 @@ > check_stack: > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, start) == 0) >+ if (expand_stack(vma, start, NULL) == 0) > goto good_area; > > bad_area: >@@ -123,7 +123,7 @@ > goto good_area; > if (!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/arch/sparc/mm/fault.c linux-2.4.22-ppc-dev/arch/sparc/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/sparc/mm/fault.c 2003-06-13 16:51:32.000000000 +0200 >+++ linux-2.4.22-ppc-dev/arch/sparc/mm/fault.c 2003-08-25 23:37:58.000000000 +0200 >@@ -251,7 +251,7 @@ > goto good_area; > if(!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if(expand_stack(vma, address)) >+ if(expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >@@ -498,7 +498,7 @@ > goto good_area; > if(!(vma->vm_flags & VM_GROWSDOWN)) > goto bad_area; >- if(expand_stack(vma, address)) >+ if(expand_stack(vma, address, NULL)) > goto bad_area; > good_area: > info.si_code = SEGV_ACCERR; >diff -Naur linux-2.4.22-ppc-dev.orig/arch/sparc64/mm/fault.c linux-2.4.22-ppc-dev/arch/sparc64/mm/fault.c >--- linux-2.4.22-ppc-dev.orig/arch/sparc64/mm/fault.c 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/arch/sparc64/mm/fault.c 2003-08-25 23:37:45.000000000 +0200 >@@ -389,7 +389,7 @@ > goto bad_area; > } > } >- if (expand_stack(vma, address)) >+ if (expand_stack(vma, address, NULL)) > goto bad_area; > /* > * Ok, we have a good vm_area for this memory access, so >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/block/ll_rw_blk.c linux-2.4.22-ppc-dev/drivers/block/ll_rw_blk.c >--- linux-2.4.22-ppc-dev.orig/drivers/block/ll_rw_blk.c 2003-08-27 15:17:50.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/block/ll_rw_blk.c 2003-08-25 23:37:41.000000000 +0200 >@@ -121,6 +121,10 @@ > unsigned long blk_max_low_pfn, blk_max_pfn; > int blk_nohighio = 0; > >+int block_dump = 0; >+ >+static struct timer_list writeback_timer; >+ > static inline int get_max_sectors(kdev_t dev) > { > if (!max_sectors[MAJOR(dev)]) >@@ -158,6 +162,12 @@ > return i; > } > >+void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) >+{ >+ q->activity_fn = fn; >+ q->activity_data = data; >+} >+ > /** > * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed > * @q: the request queue to be released >@@ -540,6 +550,7 @@ > q->head_active = 1; > > blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); >+ blk_queue_activity_fn(q, NULL, NULL); > } > > #define blkdev_free_rq(list) list_entry((list)->next, struct request, queue); >@@ -855,6 +866,9 @@ > static inline void add_request(request_queue_t * q, struct request * req, > struct list_head *insert_here) > { >+ if (q->activity_fn) >+ q->activity_fn(q->activity_data, req->cmd); >+ > drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1); > > if (!q->plugged && q->head_active && insert_here == &q->queue_head) { >@@ -1302,6 +1316,9 @@ > kstat.pgpgin += count; > break; > } >+ >+ if (block_dump) >+ printk("%s: %s block %lu/%u on %s\n", current->comm, rw == WRITE ? "WRITE" : "READ", bh->b_rsector, count, kdevname(bh->b_rdev)); > } > > /** >@@ -1413,6 +1430,11 @@ > extern int stram_device_init (void); > #endif > >+static void blk_writeback_timer(unsigned long data) >+{ >+ wakeup_bdflush(); >+ wakeup_kupdate(); >+} > > /** > * end_that_request_first - end I/O on one buffer. >@@ -1469,10 +1491,18 @@ > return 0; > } > >+extern int laptop_mode; >+ > void end_that_request_last(struct request *req) > { > struct completion *waiting = req->waiting; > >+ /* >+ * schedule the writeout of pending dirty data when the disk is idle >+ */ >+ if (laptop_mode && req->cmd == READ) >+ mod_timer(&writeback_timer, jiffies + 5 * HZ); >+ > req_finished_io(req); > blkdev_release_request(req); > if (waiting) >@@ -1500,6 +1530,9 @@ > blk_max_low_pfn = max_low_pfn - 1; > blk_max_pfn = max_pfn - 1; > >+ init_timer(&writeback_timer); >+ writeback_timer.function = blk_writeback_timer; >+ > #ifdef CONFIG_AMIGA_Z2RAM > z2_init(); > #endif >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/Config.in linux-2.4.22-ppc-dev/drivers/char/Config.in >--- linux-2.4.22-ppc-dev.orig/drivers/char/Config.in 2003-08-27 15:17:52.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/char/Config.in 2003-08-25 23:37:47.000000000 +0200 >@@ -315,6 +315,7 @@ > if [ "$CONFIG_IA64" = "y" ]; then > bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 > fi >+ dep_bool ' Apple UniNorth support' CONFIG_AGP_UNINORTH $CONFIG_ALL_PPC > fi > > bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/agp/agpgart_be.c linux-2.4.22-ppc-dev/drivers/char/agp/agpgart_be.c >--- linux-2.4.22-ppc-dev.orig/drivers/char/agp/agpgart_be.c 2003-08-27 15:17:53.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/char/agp/agpgart_be.c 2003-08-25 23:37:54.000000000 +0200 >@@ -52,6 +52,9 @@ > #ifdef CONFIG_AGP_NVIDIA > #include <asm/msr.h> > #endif >+#ifdef CONFIG_AGP_UNINORTH >+#include <asm/uninorth.h> >+#endif > > #include <linux/agp_backend.h> > #include "agp.h" >@@ -80,7 +83,7 @@ > { > #if defined(__i386__) || defined(__x86_64__) > asm volatile ("wbinvd":::"memory"); >-#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) >+#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) || defined(__powerpc__) > /* ??? I wonder if we'll really need to flush caches, or if the > core logic can manage to keep the system coherent. The ARM > speaks only of using `cflush' to get things in memory in >@@ -4735,6 +4738,405 @@ > > #endif /* CONFIG_AGP_HP_ZX1 */ > >+#ifdef CONFIG_AGP_UNINORTH >+ >+static int uninorth_fetch_size(void) >+{ >+ int i; >+ u32 temp; >+ aper_size_info_32 *values; >+ >+ pci_read_config_dword(agp_bridge.dev, UNI_N_CFG_GART_BASE, &temp); >+ temp &= ~(0xfffff000); >+ values = A_SIZE_32(agp_bridge.aperture_sizes); >+ >+ for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { >+ if (temp == values[i].size_value) { >+ agp_bridge.previous_size = >+ agp_bridge.current_size = (void *) (values + i); >+ agp_bridge.aperture_size_idx = i; >+ return values[i].size; >+ } >+ } >+ >+ agp_bridge.previous_size = >+ agp_bridge.current_size = (void *) (values + 1); >+ agp_bridge.aperture_size_idx = 1; >+ return values[1].size; >+ >+ return 0; >+} >+ >+static void uninorth_tlbflush(agp_memory * mem) >+{ >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ UNI_N_CFG_GART_ENABLE); >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET); >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ UNI_N_CFG_GART_ENABLE); >+} >+ >+static void uninorth_cleanup(void) >+{ >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ 0); >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ UNI_N_CFG_GART_2xRESET); >+ pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, >+ 0); >+} >+ >+static int uninorth_configure(void) >+{ >+ aper_size_info_32 *current_size; >+ >+ current_size = A_SIZE_32(agp_bridge.current_size); >+ >+ printk("agp: configuring for size idx: %d\n", current_size->size_value); >+ >+ /* aperture size and gatt addr */ >+ pci_write_config_dword(agp_bridge.dev, >+ UNI_N_CFG_GART_BASE, >+ (agp_bridge.gatt_bus_addr & 0xfffff000) >+ | current_size->size_value); >+ >+ /* HACK ALERT >+ * UniNorth seem to be buggy enough not to handle properly when >+ * the AGP aperture isn't mapped at bus physical address 0 >+ */ >+ agp_bridge.gart_bus_addr = 0; >+ pci_write_config_dword(agp_bridge.dev, >+ UNI_N_CFG_AGP_BASE, agp_bridge.gart_bus_addr); >+ >+ return 0; >+} >+ >+static unsigned long uninorth_mask_memory(unsigned long addr, int type) >+{ >+ return addr;/* | agp_bridge.masks[0].mask;*/ >+} >+ >+static int uninorth_insert_memory(agp_memory * mem, >+ off_t pg_start, int type) >+{ >+ int i, j, num_entries; >+ void *temp; >+ >+ temp = agp_bridge.current_size; >+ num_entries = A_SIZE_32(temp)->num_entries; >+ >+ if (type != 0 || mem->type != 0) { >+ /* The generic routines know nothing of memory types */ >+ return -EINVAL; >+ } >+ if ((pg_start + mem->page_count) > num_entries) { >+ return -EINVAL; >+ } >+ j = pg_start; >+ >+ while (j < (pg_start + mem->page_count)) { >+ if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { >+ return -EBUSY; >+ } >+ j++; >+ } >+ >+ if (mem->is_flushed == FALSE) { >+ CACHE_FLUSH(); >+ mem->is_flushed = TRUE; >+ } >+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { >+ agp_bridge.gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL); >+ flush_dcache_range(__va(mem->memory[i]), __va(mem->memory[i])+0x1000); >+ } >+ (void)in_le32((volatile u32*)&agp_bridge.gatt_table[pg_start]); >+ mb(); >+ flush_dcache_range((unsigned long)&agp_bridge.gatt_table[pg_start], >+ (unsigned long)&agp_bridge.gatt_table[pg_start + mem->page_count]); >+ >+ agp_bridge.tlb_flush(mem); >+ return 0; >+} >+ >+static void uninorth_agp_enable(u32 mode) >+{ >+ struct pci_dev *device = NULL; >+ u32 command, scratch, cap_id; >+ u8 cap_ptr; >+ >+ pci_read_config_dword(agp_bridge.dev, >+ agp_bridge.capndx + 4, >+ &command); >+ >+ /* >+ * PASS1: go throu all devices that claim to be >+ * AGP devices and collect their data. >+ */ >+ >+ while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, >+ device)) != NULL) { >+ pci_read_config_dword(device, 0x04, &scratch); >+ >+ if (!(scratch & 0x00100000)) >+ continue; >+ >+ pci_read_config_byte(device, 0x34, &cap_ptr); >+ >+ if (cap_ptr != 0x00) { >+ do { >+ pci_read_config_dword(device, >+ cap_ptr, &cap_id); >+ >+ if ((cap_id & 0xff) != 0x02) >+ cap_ptr = (cap_id >> 8) & 0xff; >+ } >+ while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); >+ } >+ if (cap_ptr != 0x00) { >+ /* >+ * Ok, here we have a AGP device. Disable impossible >+ * settings, and adjust the readqueue to the minimum. >+ */ >+ >+ pci_read_config_dword(device, cap_ptr + 4, &scratch); >+ >+ /* adjust RQ depth */ >+ command = >+ ((command & ~0xff000000) | >+ min_t(u32, (mode & 0xff000000), >+ min_t(u32, (command & 0xff000000), >+ (scratch & 0xff000000)))); >+ >+ /* disable SBA if it's not supported */ >+ if (!((command & 0x00000200) && >+ (scratch & 0x00000200) && >+ (mode & 0x00000200))) >+ command &= ~0x00000200; >+ >+ /* disable FW if it's not supported */ >+ if (!((command & 0x00000010) && >+ (scratch & 0x00000010) && >+ (mode & 0x00000010))) >+ command &= ~0x00000010; >+ >+ if (!((command & 4) && >+ (scratch & 4) && >+ (mode & 4))) >+ command &= ~0x00000004; >+ >+ if (!((command & 2) && >+ (scratch & 2) && >+ (mode & 2))) >+ command &= ~0x00000002; >+ >+ if (!((command & 1) && >+ (scratch & 1) && >+ (mode & 1))) >+ command &= ~0x00000001; >+ } >+ } >+ /* >+ * PASS2: Figure out the 4X/2X/1X setting and enable the >+ * target (our motherboard chipset). >+ */ >+ >+ if (command & 4) { >+ command &= ~3; /* 4X */ >+ } >+ if (command & 2) { >+ command &= ~5; /* 2X */ >+ } >+ if (command & 1) { >+ command &= ~6; /* 1X */ >+ } >+ command |= 0x00000100; >+ >+ uninorth_tlbflush(NULL); >+ >+ do { >+ pci_write_config_dword(agp_bridge.dev, >+ agp_bridge.capndx + 8, >+ command); >+ pci_read_config_dword(agp_bridge.dev, >+ agp_bridge.capndx + 8, >+ &scratch); >+ } while((scratch & 0x100) == 0); >+ >+ /* >+ * PASS3: Go throu all AGP devices and update the >+ * command registers. >+ */ >+ >+ while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, >+ device)) != NULL) { >+ pci_read_config_dword(device, 0x04, &scratch); >+ >+ if (!(scratch & 0x00100000)) >+ continue; >+ >+ pci_read_config_byte(device, 0x34, &cap_ptr); >+ >+ if (cap_ptr != 0x00) { >+ do { >+ pci_read_config_dword(device, >+ cap_ptr, &cap_id); >+ >+ if ((cap_id & 0xff) != 0x02) >+ cap_ptr = (cap_id >> 8) & 0xff; >+ } >+ while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); >+ } >+ if (cap_ptr != 0x00) >+ pci_write_config_dword(device, cap_ptr + 8, command); >+ } >+ >+ uninorth_tlbflush(NULL); >+} >+ >+static int uninorth_create_gatt_table(void) >+{ >+ char *table; >+ char *table_end; >+ int size; >+ int page_order; >+ int num_entries; >+ int i; >+ void *temp; >+ struct page *page; >+ >+ /* The generic routines can't handle 2 level gatt's */ >+ if (agp_bridge.size_type == LVL2_APER_SIZE) { >+ return -EINVAL; >+ } >+ >+ table = NULL; >+ i = agp_bridge.aperture_size_idx; >+ temp = agp_bridge.current_size; >+ size = page_order = num_entries = 0; >+ >+ do { >+ size = A_SIZE_32(temp)->size; >+ page_order = A_SIZE_32(temp)->page_order; >+ num_entries = A_SIZE_32(temp)->num_entries; >+ >+ table = (char *) __get_free_pages(GFP_KERNEL, page_order); >+ >+ if (table == NULL) { >+ i++; >+ agp_bridge.current_size = A_IDX32(); >+ } else { >+ agp_bridge.aperture_size_idx = i; >+ } >+ } while ((table == NULL) && >+ (i < agp_bridge.num_aperture_sizes)); >+ >+ if (table == NULL) { >+ return -ENOMEM; >+ } >+ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); >+ >+ for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) >+ SetPageReserved(page); >+ >+ agp_bridge.gatt_table_real = (unsigned long *) table; >+ agp_bridge.gatt_table = (unsigned long *)table; >+ agp_bridge.gatt_bus_addr = virt_to_phys(table); >+ >+ for (i = 0; i < num_entries; i++) { >+ agp_bridge.gatt_table[i] = >+ (unsigned long) agp_bridge.scratch_page; >+ } >+ >+ flush_dcache_range((unsigned long)table, (unsigned long)table_end); >+ >+ return 0; >+} >+ >+static int uninorth_free_gatt_table(void) >+{ >+ int page_order; >+ char *table, *table_end; >+ void *temp; >+ struct page *page; >+ >+ temp = agp_bridge.current_size; >+ page_order = A_SIZE_32(temp)->page_order; >+ >+ /* Do not worry about freeing memory, because if this is >+ * called, then all agp memory is deallocated and removed >+ * from the table. >+ */ >+ >+ table = (char *) agp_bridge.gatt_table_real; >+ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); >+ >+ for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) >+ ClearPageReserved(page); >+ >+ free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); >+ >+ return 0; >+} >+ >+ >+/* Setup function */ >+static gatt_mask uninorth_masks[] = >+{ >+ {0x00000000, 0} >+}; >+ >+static aper_size_info_32 uninorth_sizes[7] = >+{ >+#if 0 /* Not sure uninorth supports that high aperture sizes */ >+ {256, 65536, 6, 64}, >+ {128, 32768, 5, 32}, >+ {64, 16384, 4, 16}, >+#endif >+ {32, 8192, 3, 8}, >+ {16, 4096, 2, 4}, >+ {8, 2048, 1, 2}, >+ {4, 1024, 0, 1} >+}; >+ >+static int __init uninorth_setup (struct pci_dev *pdev) >+{ >+ agp_bridge.masks = uninorth_masks; >+ agp_bridge.aperture_sizes = (void *)uninorth_sizes; >+ agp_bridge.size_type = U32_APER_SIZE; >+ agp_bridge.num_aperture_sizes = 4; //7; >+ agp_bridge.dev_private_data = NULL; >+ agp_bridge.needs_scratch_page = FALSE; >+ agp_bridge.configure = uninorth_configure; >+ agp_bridge.fetch_size = uninorth_fetch_size; >+ agp_bridge.cleanup = uninorth_cleanup; >+ agp_bridge.tlb_flush = uninorth_tlbflush; >+ agp_bridge.mask_memory = uninorth_mask_memory; >+ agp_bridge.agp_enable = uninorth_agp_enable; >+ agp_bridge.cache_flush = global_cache_flush; >+ agp_bridge.create_gatt_table = uninorth_create_gatt_table; >+ agp_bridge.free_gatt_table = uninorth_free_gatt_table; >+ agp_bridge.insert_memory = uninorth_insert_memory; >+ agp_bridge.remove_memory = agp_generic_remove_memory; >+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type; >+ agp_bridge.free_by_type = agp_generic_free_by_type; >+ agp_bridge.agp_alloc_page = agp_generic_alloc_page; >+ agp_bridge.agp_destroy_page = agp_generic_destroy_page; >+ agp_bridge.suspend = agp_generic_suspend; >+ agp_bridge.resume = agp_generic_resume; >+ agp_bridge.cant_use_aperture = 1; >+ >+ return 0; >+ >+ (void) pdev; /* unused */ >+} >+ >+#endif /* CONFIG_AGP_UNINORTH */ >+ > /* per-chipset initialization data. > * note -- all chipsets for a single vendor MUST be grouped together > */ >@@ -5167,6 +5569,33 @@ > hp_zx1_setup }, > #endif > >+#ifdef CONFIG_AGP_UNINORTH >+ { PCI_DEVICE_ID_APPLE_UNI_N_AGP, >+ PCI_VENDOR_ID_APPLE, >+ APPLE_UNINORTH, >+ "Apple", >+ "UniNorth", >+ uninorth_setup }, >+ { PCI_DEVICE_ID_APPLE_UNI_N_AGP_P, >+ PCI_VENDOR_ID_APPLE, >+ APPLE_UNINORTH, >+ "Apple", >+ "UniNorth/Pangea", >+ uninorth_setup }, >+ { PCI_DEVICE_ID_APPLE_UNI_N_AGP15, >+ PCI_VENDOR_ID_APPLE, >+ APPLE_UNINORTH, >+ "Apple", >+ "UniNorth 1.5", >+ uninorth_setup }, >+ { PCI_DEVICE_ID_APPLE_UNI_N_AGP2, >+ PCI_VENDOR_ID_APPLE, >+ APPLE_UNINORTH, >+ "Apple", >+ "UniNorth 2", >+ uninorth_setup }, >+#endif /* CONFIG_AGP_UNINORTH */ >+ > { 0, }, /* dummy final entry, always present */ > }; > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/defkeymap.c linux-2.4.22-ppc-dev/drivers/char/defkeymap.c >--- linux-2.4.22-ppc-dev.orig/drivers/char/defkeymap.c 1999-10-07 19:17:09.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/char/defkeymap.c 2003-08-25 23:38:00.000000000 +0200 >@@ -1,3 +1,4 @@ >+ > /* Do not edit this file! It was automatically generated by */ > /* loadkeys --mktable defkeymap.map > defkeymap.c */ > >@@ -37,7 +38,7 @@ > 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, > 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, > 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >- 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, >+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, > 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, > 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, > 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >@@ -56,7 +57,7 @@ > 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, > 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, > 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >- 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, >+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, > 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, > 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, > 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >@@ -94,7 +95,7 @@ > 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, > 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, > 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >- 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, >+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, > 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, > 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, > 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >@@ -132,7 +133,7 @@ > 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, > 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, > 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >- 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, >+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, > 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, > 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, > 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, >@@ -147,6 +148,7 @@ > > unsigned int keymap_count = 7; > >+ > /* > * Philosophy: most people do not define more strings, but they who do > * often want quite a lot of string space. So, we statically allocate >@@ -184,6 +186,7 @@ > '\033', '[', 'P', 0, > }; > >+ > char *funcbufptr = func_buf; > int funcbufsize = sizeof(func_buf); > int funcbufleft = 0; /* space left */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/drmP.h linux-2.4.22-ppc-dev/drivers/char/drm/drmP.h >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/drmP.h 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/drmP.h 2003-08-25 23:37:33.000000000 +0200 >@@ -324,6 +324,15 @@ > DRM(ioremapfree)( (map)->handle, (map)->size ); \ > } while (0) > >+#define DRM_IOREMAPAGP(map, dev) \ >+ (map)->handle = DRM(ioremap_agp)( (map)->offset, (map)->size, (dev) ) >+ >+#define DRM_IOREMAPAGPFREE(map) \ >+ do { \ >+ if ( (map)->handle && (map)->size ) \ >+ DRM(ioremap_agp_free)( (map)->handle, (map)->size ); \ >+ } while (0) >+ > #define DRM_FIND_MAP(_map, _o) \ > do { \ > struct list_head *_list; \ >@@ -758,6 +767,9 @@ > extern void *DRM(ioremap)(unsigned long offset, unsigned long size); > extern void DRM(ioremapfree)(void *pt, unsigned long size); > >+extern void *DRM(ioremap_agp)(unsigned long offset, unsigned long size, drm_device_t *dev); >+extern void DRM(ioremap_agp_free)(void *pt, unsigned long size); >+ > #if __REALLY_HAVE_AGP > extern agp_memory *DRM(alloc_agp)(int pages, u32 type); > extern int DRM(free_agp)(agp_memory *handle, int pages); >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/drm_memory.h linux-2.4.22-ppc-dev/drivers/char/drm/drm_memory.h >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/drm_memory.h 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/drm_memory.h 2003-08-25 23:37:36.000000000 +0200 >@@ -313,6 +313,108 @@ > return pt; > } > >+/* PPC specific routine used by ioremap_agp, to be replaced by some >+ * more generic implementation >+ */ >+extern int map_page(unsigned long va, unsigned long pa, int flags); >+ >+void *DRM(ioremap_agp)(unsigned long offset, unsigned long size, drm_device_t *dev) >+{ >+ void *pt; >+ struct vm_struct *area; >+ struct drm_agp_mem *agpmem; >+ unsigned int flags = _PAGE_NO_CACHE|_PAGE_KERNEL|_PAGE_PRESENT|_PAGE_RW|_PAGE_DIRTY; >+ int err, i; >+ >+ printk("drm: ioremap_agp, offset: 0x%08lx, size: 0x%08lx\n", offset, size); >+ >+#if __REALLY_HAVE_AGP >+ if (!size) { >+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS, >+ "Mapping 0 bytes at 0x%08lx\n", offset); >+ return NULL; >+ } >+ >+ if (!dev->agp || !dev->agp->cant_use_aperture) >+ return DRM(ioremap)(offset, size); >+ >+ /* XXX This has to be changed into something more generic >+ * this implementation is really only valid on PPC >+ */ >+ area = get_vm_area(size, VM_IOREMAP); >+ if (area == 0) { >+ spin_lock(&DRM(mem_lock)); >+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; >+ spin_unlock(&DRM(mem_lock)); >+ printk("->NULL\n"); >+ return NULL; >+ } >+ pt = (void *)VMALLOC_VMADDR(area->addr); >+ err = 0; >+ for (i = 0; i < size && err == 0; i += PAGE_SIZE) { >+ unsigned long baddr = offset + i; >+ unsigned long index; >+ >+ /* >+ * It's AGP memory - find the real physical page to map >+ */ >+ for(agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { >+ if (agpmem->bound <= baddr && >+ agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) >+ break; >+ } >+ if (!agpmem) { >+ printk("drm: not matching AGP page in ioremap_agp\n"); >+ err = 1; >+ break; >+ } >+ index = (baddr - agpmem->bound) >> PAGE_SHIFT; >+ get_page(virt_to_page(__va(agpmem->memory->memory[index]))); >+ err = map_page(((unsigned long)pt)+i, agpmem->memory->memory[index], flags); >+ } >+ if (err) { >+ vfree((void *)pt); >+ spin_lock(&DRM(mem_lock)); >+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; >+ spin_unlock(&DRM(mem_lock)); >+ printk("->NULL\n"); >+ return NULL; >+ } >+ >+ spin_lock(&DRM(mem_lock)); >+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; >+ DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; >+ spin_unlock(&DRM(mem_lock)); >+ printk("->pt=0x%p\n", pt); >+ return pt; >+#else >+ return NULL; >+#endif >+} >+ >+void DRM(ioremap_agp_free)(void *pt, unsigned long size) >+{ >+ int alloc_count; >+ int free_count; >+ >+ if (!pt) >+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS, >+ "Attempt to free NULL pointer\n"); >+ else >+ vfree(pt); >+ >+ spin_lock(&DRM(mem_lock)); >+ DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; >+ free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; >+ alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; >+ spin_unlock(&DRM(mem_lock)); >+ if (free_count > alloc_count) { >+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS, >+ "Excess frees: %d frees, %d allocs\n", >+ free_count, alloc_count); >+ } >+} >+ > void DRM(ioremapfree)(void *pt, unsigned long size) > { > int alloc_count; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/drm_vm.h linux-2.4.22-ppc-dev/drivers/char/drm/drm_vm.h >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/drm_vm.h 2003-06-13 16:51:32.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/drm_vm.h 2003-08-25 23:38:10.000000000 +0200 >@@ -379,7 +379,13 @@ > > if ( !priv->authenticated ) return -EACCES; > >- if (!VM_OFFSET(vma)) return DRM(mmap_dma)(filp, vma); >+ /* We check for "dma". On Apple's UniNorth, it's valid to have >+ * the AGP mapped at physical address 0 >+ * --BenH. >+ */ >+ if (!VM_OFFSET(vma) && (!dev->agp || >+ dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)) >+ return DRM(mmap_dma)(filp, vma); > > /* A sequential search of a linked list is > fine here because: 1) there will only be >@@ -419,16 +425,22 @@ > > switch (map->type) { > case _DRM_AGP: >-#if defined(__alpha__) >- /* >- * On Alpha we can't talk to bus dma address from the >- * CPU, so for memory of type DRM_AGP, we'll deal with >- * sorting out the real physical pages and mappings >- * in nopage() >- */ >- vma->vm_ops = &DRM(vm_ops); >- break; >+ if (!dev->agp) >+ return -ENODEV; >+ if (dev->agp->cant_use_aperture) { >+ /* >+ * On Alpha we can't talk to bus dma address from the >+ * CPU, so for memory of type DRM_AGP, we'll deal with >+ * sorting out the real physical pages and mappings >+ * in nopage() >+ */ >+#if defined(__powerpc__) >+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; > #endif >+ vma->vm_flags |= VM_IO; >+ vma->vm_ops = &DRM(vm_ops); >+ break; >+ } > /* fall through to _DRM_FRAME_BUFFER... */ > case _DRM_FRAME_BUFFER: > case _DRM_REGISTERS: >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/r128_cce.c linux-2.4.22-ppc-dev/drivers/char/drm/r128_cce.c >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/r128_cce.c 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/r128_cce.c 2003-08-25 23:37:27.000000000 +0200 >@@ -37,6 +37,10 @@ > > #define R128_FIFO_DEBUG 0 > >+#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) >+extern unsigned long agp_special_page; >+#endif >+ > > /* CCE microcode (from ATI) */ > static u32 r128_cce_microcode[] = { >@@ -340,6 +344,14 @@ > SET_RING_HEAD( &dev_priv->ring, 0 ); > > if ( !dev_priv->is_pci ) { >+#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) >+ if (_machine == _MACH_Pmac) { >+ dev_priv->ring.head = (__volatile__ u32 *) agp_special_page; >+ SET_RING_HEAD( &dev_priv->ring, 0 ); >+ R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, >+ __pa( dev_priv->ring.head ) ); >+ } else >+#endif > R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, > dev_priv->ring_rptr->offset ); > } else { >@@ -549,9 +561,9 @@ > init->sarea_priv_offset); > > if ( !dev_priv->is_pci ) { >- DRM_IOREMAP( dev_priv->cce_ring ); >- DRM_IOREMAP( dev_priv->ring_rptr ); >- DRM_IOREMAP( dev_priv->buffers ); >+ DRM_IOREMAPAGP( dev_priv->cce_ring, dev ); >+ DRM_IOREMAPAGP( dev_priv->ring_rptr, dev ); >+ DRM_IOREMAPAGP( dev_priv->buffers, dev ); > if(!dev_priv->cce_ring->handle || > !dev_priv->ring_rptr->handle || > !dev_priv->buffers->handle) { >@@ -623,10 +635,11 @@ > drm_r128_private_t *dev_priv = dev->dev_private; > > if ( !dev_priv->is_pci ) { >- DRM_IOREMAPFREE( dev_priv->cce_ring ); >- DRM_IOREMAPFREE( dev_priv->ring_rptr ); >- DRM_IOREMAPFREE( dev_priv->buffers ); >- } else { >+ DRM_IOREMAPAGPFREE( dev_priv->cce_ring ); >+ DRM_IOREMAPAGPFREE( dev_priv->ring_rptr ); >+ DRM_IOREMAPAGPFREE( dev_priv->buffers ); >+ } >+ else { > if (!DRM(ati_pcigart_cleanup)( dev, > dev_priv->phys_pci_gart, > dev_priv->bus_pci_gart )) >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/r128_drv.h linux-2.4.22-ppc-dev/drivers/char/drm/r128_drv.h >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/r128_drv.h 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/r128_drv.h 2003-08-25 23:37:54.000000000 +0200 >@@ -34,8 +34,13 @@ > #ifndef __R128_DRV_H__ > #define __R128_DRV_H__ > >+#ifdef __powerpc__ >+#define GET_RING_HEAD( ring ) in_le32((volatile u32 *)(ring)->head) >+#define SET_RING_HEAD( ring, val ) out_le32((volatile u32 *)(ring)->head, (val) ) >+#else > #define GET_RING_HEAD( ring ) le32_to_cpu( *(ring)->head ) > #define SET_RING_HEAD( ring, val ) *(ring)->head = cpu_to_le32( val ) >+#endif > > typedef struct drm_r128_freelist { > unsigned int age; >@@ -397,6 +402,9 @@ > wmb(); \ > R128_DEREF(reg) = val; \ > } while (0) >+#elif defined (__powerpc__) >+#define R128_READ(reg) in_le32( (volatile u32 *)R128_ADDR( reg ) ) >+#define R128_WRITE(reg,val) out_le32( (volatile u32 *)R128_ADDR( reg ), (val) ) > #else > #define R128_READ(reg) le32_to_cpu( R128_DEREF( reg ) ) > #define R128_WRITE(reg,val) \ >@@ -418,6 +426,9 @@ > wmb(); \ > R128_DEREF8(reg) = val; \ > } while (0) >+#elif defined (__powerpc__) >+#define R128_READ8(reg) in_8( (volatile u8 *)R128_ADDR(reg) ) >+#define R128_WRITE8(reg,val) out_8( (volatile u8 *)R128_ADDR(reg), val ) > #else > #define R128_READ8(reg) R128_DEREF8( reg ) > #define R128_WRITE8(reg,val) do { R128_DEREF8( reg ) = val; } while (0) >@@ -493,8 +504,11 @@ > * Ring control > */ > >+#ifdef __powerpc__ >+#define r128_flush_write_combine() (void)in_le32(ring) >+#else > #define r128_flush_write_combine() mb() >- >+#endif > > #define R128_VERBOSE 0 > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/radeon_cp.c linux-2.4.22-ppc-dev/drivers/char/drm/radeon_cp.c >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/radeon_cp.c 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/radeon_cp.c 2003-08-25 23:37:49.000000000 +0200 >@@ -37,12 +37,15 @@ > > #define RADEON_FIFO_DEBUG 0 > >-#if defined(__alpha__) >+#if defined(__alpha__) || defined(__powerpc__) > # define PCIGART_ENABLED > #else > # undef PCIGART_ENABLED > #endif > >+#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) >+extern unsigned long agp_special_page; >+#endif > > /* CP microcode (from ATI) */ > static u32 radeon_cp_microcode[][2] = { >@@ -313,7 +316,7 @@ > return RADEON_READ(RADEON_CLOCK_CNTL_DATA); > } > >-#if RADEON_FIFO_DEBUG >+#if 1 /* RADEON_FIFO_DEBUG */ > static void radeon_status( drm_radeon_private_t *dev_priv ) > { > printk( "%s:\n", __FUNCTION__ ); >@@ -400,7 +403,8 @@ > udelay( 1 ); > } > >-#if RADEON_FIFO_DEBUG >+#if 1 /* RADEON_FIFO_DEBUG */ >+ printk("wait_for_idle timeout\n"); > DRM_ERROR( "failed!\n" ); > radeon_status( dev_priv ); > #endif >@@ -611,6 +615,14 @@ > dev_priv->ring.tail = cur_read_ptr; > > if ( !dev_priv->is_pci ) { >+#if __REALLY_HAVE_AGP && defined(CONFIG_ALL_PPC) >+ if (_machine == _MACH_Pmac) { >+ dev_priv->ring.head = (__volatile__ u32 *) agp_special_page; >+ *dev_priv->ring.head = cur_read_ptr; >+ RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, >+ __pa( dev_priv->ring.head ) ); >+ } else >+#endif > RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, > dev_priv->ring_rptr->offset ); > } else { >@@ -835,9 +847,9 @@ > init->sarea_priv_offset); > > if ( !dev_priv->is_pci ) { >- DRM_IOREMAP( dev_priv->cp_ring ); >- DRM_IOREMAP( dev_priv->ring_rptr ); >- DRM_IOREMAP( dev_priv->buffers ); >+ DRM_IOREMAPAGP( dev_priv->cp_ring, dev ); >+ DRM_IOREMAPAGP( dev_priv->ring_rptr, dev ); >+ DRM_IOREMAPAGP( dev_priv->buffers, dev ); > if(!dev_priv->cp_ring->handle || > !dev_priv->ring_rptr->handle || > !dev_priv->buffers->handle) { >@@ -982,9 +994,9 @@ > drm_radeon_private_t *dev_priv = dev->dev_private; > > if ( !dev_priv->is_pci ) { >- DRM_IOREMAPFREE( dev_priv->cp_ring ); >- DRM_IOREMAPFREE( dev_priv->ring_rptr ); >- DRM_IOREMAPFREE( dev_priv->buffers ); >+ DRM_IOREMAPAGPFREE( dev_priv->cp_ring ); >+ DRM_IOREMAPAGPFREE( dev_priv->ring_rptr ); >+ DRM_IOREMAPAGPFREE( dev_priv->buffers ); > } else { > if (!DRM(ati_pcigart_cleanup)( dev, > dev_priv->phys_pci_gart, >@@ -1351,14 +1363,15 @@ > int i; > > for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { >- radeon_update_ring_snapshot( ring ); >+ radeon_update_ring_snapshot( dev_priv, ring ); > if ( ring->space > n ) > return 0; > udelay( 1 ); > } > > /* FIXME: This return value is ignored in the BEGIN_RING macro! */ >-#if RADEON_FIFO_DEBUG >+#if 1 /* RADEON_FIFO_DEBUG */ >+ printk("wait ring timeout\n"); > radeon_status( dev_priv ); > DRM_ERROR( "failed!\n" ); > #endif >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/radeon_drv.h linux-2.4.22-ppc-dev/drivers/char/drm/radeon_drv.h >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/radeon_drv.h 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/radeon_drv.h 2003-08-25 23:37:30.000000000 +0200 >@@ -31,6 +31,14 @@ > #ifndef __RADEON_DRV_H__ > #define __RADEON_DRV_H__ > >+#if defined(__powerpc__) >+#define GET_RING_HEAD(ring) in_le32((volatile u32 *)(ring)->head) >+#define SET_RING_HEAD(ring,val) out_le32((volatile u32 *)(ring)->head, (val)) >+#else >+#define GET_RING_HEAD(ring) le32_to_cpu(*(ring)->head) >+#define SET_RING_HEAD(ring,val) *(ring)->head = cpu_to_le32(val) >+#endif >+ > typedef struct drm_radeon_freelist { > unsigned int age; > drm_buf_t *buf; >@@ -150,12 +158,7 @@ > extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ); > > static inline void >-radeon_update_ring_snapshot( drm_radeon_ring_buffer_t *ring ) >-{ >- ring->space = (*(volatile int *)ring->head - ring->tail) * sizeof(u32); >- if ( ring->space <= 0 ) >- ring->space += ring->size; >-} >+radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv, drm_radeon_ring_buffer_t *ring ); > > extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ); > extern int radeon_do_cleanup_cp( drm_device_t *dev ); >@@ -539,6 +542,9 @@ > wmb(); \ > RADEON_DEREF(reg) = val; \ > } while (0) >+#elif defined(__powerpc__) >+#define RADEON_READ(reg) in_le32((volatile u32 *)RADEON_ADDR(reg)) >+#define RADEON_WRITE(reg,val) out_le32((volatile u32 *)RADEON_ADDR(reg), (val)) > #else > #define RADEON_READ(reg) RADEON_DEREF( reg ) > #define RADEON_WRITE(reg, val) do { RADEON_DEREF( reg ) = val; } while (0) >@@ -557,6 +563,9 @@ > wmb(); \ > RADEON_DEREF8( reg ) = val; \ > } while (0) >+#elif defined(__powerpc__) >+#define RADEON_READ8(reg) in_8((volatile u8 *)RADEON_ADDR(reg)) >+#define RADEON_WRITE8(reg,val) out_8((volatile u8 *)RADEON_ADDR(reg), (val)) > #else > #define RADEON_READ8(reg) RADEON_DEREF8( reg ) > #define RADEON_WRITE8(reg, val) do { RADEON_DEREF8( reg ) = val; } while (0) >@@ -652,7 +661,7 @@ > drm_radeon_ring_buffer_t *ring = &dev_priv->ring; int i; \ > if ( ring->space < ring->high_mark ) { \ > for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \ >- radeon_update_ring_snapshot( ring ); \ >+ radeon_update_ring_snapshot( dev_priv, ring ); \ > if ( ring->space >= ring->high_mark ) \ > goto __ring_space_done; \ > udelay( 1 ); \ >@@ -694,12 +703,28 @@ > * Ring control > */ > >+#if defined(__powerpc__) >+#define radeon_flush_write_combine() do { mb(); (void)in_le32(ring); mb(); } while(0) >+#else > #define radeon_flush_write_combine() mb() >- >+#endif > > #define RADEON_VERBOSE 0 >+#define RADEON_DEBUG > >+#ifdef RADEON_DEBUG >+#define RING_LOCALS int write; unsigned int mask; volatile u32 *ring; int dbg; >+#define DEBUG_INIT(n) dbg = n >+#define DEBUG_INC() do { if (dbg <= 0) printk("Argh 1 ! (%s:%d)\n", __FILE__, __LINE__); \ >+ dbg--; } while(0) >+#define DEBUG_END() do { if (dbg != 0) printk("Argh 2/%d ! (%s:%d)\n", dbg, __FILE__, __LINE__); \ >+ dbg--; } while(0) >+#else > #define RING_LOCALS int write; unsigned int mask; volatile u32 *ring; >+#define DEBUG_INIT() >+#define DEBUG_INC() >+#define DEBUG_END() >+#endif > > #define BEGIN_RING( n ) do { \ > if ( RADEON_VERBOSE ) { \ >@@ -713,6 +738,7 @@ > ring = dev_priv->ring.start; \ > write = dev_priv->ring.tail; \ > mask = dev_priv->ring.tail_mask; \ >+ DEBUG_INIT(n); \ > } while (0) > > #define ADVANCE_RING() do { \ >@@ -720,6 +746,7 @@ > DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ > write, dev_priv->ring.tail ); \ > } \ >+ DEBUG_END(); \ > radeon_flush_write_combine(); \ > dev_priv->ring.tail = write; \ > RADEON_WRITE( RADEON_CP_RB_WPTR, write ); \ >@@ -730,10 +757,20 @@ > DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ > (unsigned int)(x), write ); \ > } \ >- ring[write++] = (x); \ >+ DEBUG_INC(); \ >+ ring[write++] = cpu_to_le32(x); \ > write &= mask; \ > } while (0) > > #define RADEON_PERFORMANCE_BOXES 0 > >+static inline void >+radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv, drm_radeon_ring_buffer_t *ring ) >+{ >+// ring->space = (GET_RING_HEAD(ring) - ring->tail) * sizeof(u32); >+ ring->space = (RADEON_READ(0x710) - ring->tail) * sizeof(u32); >+ if ( ring->space <= 0 ) >+ ring->space += ring->size; >+} >+ > #endif /* __RADEON_DRV_H__ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/char/drm/radeon_state.c linux-2.4.22-ppc-dev/drivers/char/drm/radeon_state.c >--- linux-2.4.22-ppc-dev.orig/drivers/char/drm/radeon_state.c 2002-11-29 00:53:12.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/char/drm/radeon_state.c 2003-08-25 23:37:48.000000000 +0200 >@@ -849,7 +849,7 @@ > u32 *data = (u32 *) > ((char *)dev_priv->buffers->handle > + buf->offset + start); >- data[dwords++] = RADEON_CP_PACKET2; >+ data[dwords++] = cpu_to_le32(RADEON_CP_PACKET2); > } > > buf_priv->dispatched = 1; >@@ -913,18 +913,22 @@ > data = (u32 *)((char *)dev_priv->buffers->handle > + buf->offset + start); > >- data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 ); >+ data[0] = cpu_to_le32(CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 )); > >- data[1] = offset; >- data[2] = RADEON_MAX_VB_VERTS; >- data[3] = format; >- data[4] = (prim | RADEON_PRIM_WALK_IND | >+ data[1] = cpu_to_le32(offset); >+ data[2] = cpu_to_le32(RADEON_MAX_VB_VERTS); >+ data[3] = cpu_to_le32(format); >+ data[4] = cpu_to_le32((prim | RADEON_PRIM_WALK_IND | > RADEON_COLOR_ORDER_RGBA | > RADEON_VTX_FMT_RADEON_MODE | >- (count << RADEON_NUM_VERTICES_SHIFT) ); >+ (count << RADEON_NUM_VERTICES_SHIFT) )); > > if ( count & 0x1 ) { >+#ifdef __LITTLE_ENDIAN > data[dwords-1] &= 0x0000ffff; >+#else >+ data[dwords-1] &= 0xffff0000; >+#endif > } > > do { >@@ -1067,22 +1071,22 @@ > */ > buffer = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); > >- buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); >- buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | >+ buffer[0] = cpu_to_le32(CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 )); >+ buffer[1] = cpu_to_le32((RADEON_GMC_DST_PITCH_OFFSET_CNTL | > RADEON_GMC_BRUSH_NONE | > (format << 8) | > RADEON_GMC_SRC_DATATYPE_COLOR | > RADEON_ROP3_S | > RADEON_DP_SRC_SOURCE_HOST_DATA | > RADEON_GMC_CLR_CMP_CNTL_DIS | >- RADEON_GMC_WR_MSK_DIS); >+ RADEON_GMC_WR_MSK_DIS)); > >- buffer[2] = (tex->pitch << 22) | (tex->offset >> 10); >- buffer[3] = 0xffffffff; >- buffer[4] = 0xffffffff; >- buffer[5] = (y << 16) | image->x; >- buffer[6] = (height << 16) | image->width; >- buffer[7] = dwords; >+ buffer[2] = cpu_to_le32((tex->pitch << 22) | (tex->offset >> 10)); >+ buffer[3] = cpu_to_le32(0xffffffff); >+ buffer[4] = cpu_to_le32(0xffffffff); >+ buffer[5] = cpu_to_le32((y << 16) | image->x); >+ buffer[6] = cpu_to_le32((height << 16) | image->width); >+ buffer[7] = cpu_to_le32(dwords); > > buffer += 8; > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/i2c/i2c-keywest.c linux-2.4.22-ppc-dev/drivers/i2c/i2c-keywest.c >--- linux-2.4.22-ppc-dev.orig/drivers/i2c/i2c-keywest.c 2002-11-29 00:53:13.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/i2c/i2c-keywest.c 2003-08-25 23:37:30.000000000 +0200 >@@ -256,6 +256,7 @@ > len = 1; > buffer = &data->byte; > iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; >+ //iface->cur_mode |= KW_I2C_MODE_COMBINED; > break; > case I2C_SMBUS_WORD_DATA: > len = 2; >@@ -267,6 +268,7 @@ > len = data->block[0]; > buffer = &data->block[1]; > iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; >+ //iface->cur_mode |= KW_I2C_MODE_COMBINED; > break; > default: > return -1; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/ide/Config.in linux-2.4.22-ppc-dev/drivers/ide/Config.in >--- linux-2.4.22-ppc-dev.orig/drivers/ide/Config.in 2003-08-27 15:17:54.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/ide/Config.in 2003-08-25 23:37:29.000000000 +0200 >@@ -86,6 +86,9 @@ > dep_bool ' Probe internal Kauai ATA/100 first' CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST $CONFIG_BLK_DEV_IDE_PMAC > dep_bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC > dep_bool ' Use DMA by default' CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC >+ if [ "$CONFIG_ADB_PMU" = "y" ]; then >+ bool ' Blink laptop LED on activity' CONFIG_PMU_HD_BLINK >+ fi > if [ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" ]; then > define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC > fi >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/ide/arm/rapide.c linux-2.4.22-ppc-dev/drivers/ide/arm/rapide.c >--- linux-2.4.22-ppc-dev.orig/drivers/ide/arm/rapide.c 2003-06-13 16:51:33.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/ide/arm/rapide.c 2003-08-25 23:37:29.000000000 +0200 >@@ -40,6 +40,7 @@ > } > hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206; > hw.irq = ec->irq; >+ hw.chipset = ide_generic; > > return ide_register_hw(&hw, NULL); > } >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/ide/ide-disk.c linux-2.4.22-ppc-dev/drivers/ide/ide-disk.c >--- linux-2.4.22-ppc-dev.orig/drivers/ide/ide-disk.c 2003-06-13 16:51:33.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/ide/ide-disk.c 2003-08-25 23:37:31.000000000 +0200 >@@ -1161,13 +1161,17 @@ > { > struct hd_driveid *id = drive->id; > unsigned long capacity = drive->cyl * drive->head * drive->sect; >- unsigned long set_max = idedisk_read_native_max_address(drive); >+ unsigned long set_max = 0; > unsigned long long capacity_2 = capacity; > unsigned long long set_max_ext; > > drive->capacity48 = 0; > drive->select.b.lba = 0; > >+ /* That stupid compact flash doesn't like the command */ >+ if (!drive->is_flash) >+ set_max = idedisk_read_native_max_address(drive); >+ > (void) idedisk_supports_host_protected_area(drive); > > if (id->cfs_enable_2 & 0x0400) { >@@ -1566,7 +1570,7 @@ > > static int set_lba_addressing (ide_drive_t *drive, int arg) > { >- return (probe_lba_addressing(drive, arg)); >+ return probe_lba_addressing(drive, arg); > } > > static void idedisk_add_settings(ide_drive_t *drive) >@@ -1644,13 +1648,20 @@ > break; > } > >-#if 1 > (void) probe_lba_addressing(drive, 1); >-#else >- /* if using 48-bit addressing bump the request size up */ >- if (probe_lba_addressing(drive, 1)) >- blk_queue_max_sectors(&drive->queue, 2048); >-#endif >+ >+ if (drive->addressing == 1) { >+ int max_s = 2048, i, off = drive->select.b.unit << PARTN_BITS; >+ ide_hwif_t *hwif = HWIF(drive); >+ >+ if (max_s > hwif->rqsize) >+ max_s = hwif->rqsize; >+ >+ for (i = 0; i < (1 << PARTN_BITS); i++) >+ max_sectors[hwif->major][off + i] = max_s; >+ >+ printk("%s: max request size: %dKiB\n", drive->name, max_s / 2); >+ } > > /* Extract geometry if we did not already have one for the drive */ > if (!drive->cyl || !drive->head || !drive->sect) { >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/ide/ide-probe.c linux-2.4.22-ppc-dev/drivers/ide/ide-probe.c >--- linux-2.4.22-ppc-dev.orig/drivers/ide/ide-probe.c 2003-08-27 15:17:54.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/ide/ide-probe.c 2003-08-25 23:37:48.000000000 +0200 >@@ -972,6 +972,11 @@ > q->queuedata = HWGROUP(drive); > blk_init_queue(q, do_ide_request); > blk_queue_throttle_sectors(q, 1); >+ /* >+ * enable led activity for disk drives only >+ */ >+ if (drive->media == ide_disk && HWIF(drive)->led_act) >+ blk_queue_activity_fn(&drive->queue, HWIF(drive)->led_act, drive); > } > > #undef __IRQ_HELL_SPIN >@@ -1164,6 +1169,9 @@ > > units = MAX_DRIVES; > >+ if (!hwif->rqsize) >+ hwif->rqsize = hwif->addressing ? 128 : 65536; >+ > minors = units * (1<<PARTN_BITS); > gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL); > if (!gd) >@@ -1193,11 +1201,14 @@ > max_sectors[hwif->major] = max_sect; > max_readahead[hwif->major] = max_ra; > for (unit = 0; unit < minors; ++unit) { >+ int max_s = 128; >+ > *bs++ = BLOCK_SIZE; >- /* >- * IDE can do up to 128K per request == 256 >- */ >- *max_sect++ = ((hwif->rqsize) ? hwif->rqsize : 128); >+ >+ if (max_s > hwif->rqsize) >+ max_s = hwif->rqsize; >+ >+ *max_sect++ = max_s; > *max_ra++ = vm_max_readahead; > } > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/ide/ppc/pmac.c linux-2.4.22-ppc-dev/drivers/ide/ppc/pmac.c >--- linux-2.4.22-ppc-dev.orig/drivers/ide/ppc/pmac.c 2003-06-13 16:51:34.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/ide/ppc/pmac.c 2003-08-25 23:37:27.000000000 +0200 >@@ -38,10 +38,8 @@ > #include <asm/pmac_feature.h> > #include <asm/sections.h> > #include <asm/irq.h> >-#ifdef CONFIG_PMAC_PBOOK > #include <linux/adb.h> > #include <linux/pmu.h> >-#endif > #include "ide_modes.h" > #include "ide-timing.h" > >@@ -357,6 +355,89 @@ > }; > #endif /* CONFIG_PMAC_PBOOK */ > >+#ifdef CONFIG_PMU_HD_BLINK >+ >+/* Set to 50ms */ >+#define PMU_HD_BLINK_TIME (HZ/20) >+ >+static struct adb_request pmu_blink_on, pmu_blink_off; >+static spinlock_t pmu_blink_lock; >+static unsigned long pmu_blink_stoptime; >+static int pmu_blink_ledstate; >+static struct timer_list pmu_blink_timer; >+ >+static void >+pmu_hd_blink_timeout(unsigned long data) >+{ >+ unsigned long flags; >+ >+ spin_lock_irqsave(&pmu_blink_lock, flags); >+ >+ /* We may have been triggered again in a racy way, check >+ * that we really want to switch it off >+ */ >+ if (time_after(pmu_blink_stoptime, jiffies)) >+ goto done; >+ >+ /* Previous req. not complete, try 50ms more */ >+ if (pmu_blink_off.complete == 0) >+ mod_timer(&pmu_blink_timer, jiffies + PMU_HD_BLINK_TIME); >+ else if (pmu_blink_ledstate) { >+ pmu_request(&pmu_blink_off, NULL, 4, 0xee, 4, 0, 0); >+ pmu_blink_ledstate = 0; >+ } >+done: >+ spin_unlock_irqrestore(&pmu_blink_lock, flags); >+} >+ >+static void >+pmu_hd_kick_blink(void *data, int rw) >+{ >+ unsigned long flags; >+ >+ pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME; >+ wmb(); >+ mod_timer(&pmu_blink_timer, pmu_blink_stoptime); >+ if (pmu_blink_ledstate == 1) >+ return; >+ spin_lock_irqsave(&pmu_blink_lock, flags); >+ if (pmu_blink_on.complete && !pmu_blink_ledstate) { >+ pmu_request(&pmu_blink_on, NULL, 4, 0xee, 4, 0, 1); >+ pmu_blink_ledstate = 1; >+ } >+ spin_unlock_irqrestore(&pmu_blink_lock, flags); >+} >+ >+static int >+pmu_hd_blink_init(void) >+{ >+ struct device_node *dt; >+ const char *model; >+ >+ if (pmu_get_model() != PMU_KEYLARGO_BASED) >+ return 0; >+ >+ dt = find_devices("device-tree"); >+ if (dt == NULL) >+ return 0; >+ model = (const char *)get_property(dt, "model", NULL); >+ if (model == NULL) >+ return 0; >+ if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && >+ strncmp(model, "iBook", strlen("iBook")) != 0) >+ return 0; >+ >+ pmu_blink_on.complete = 1; >+ pmu_blink_off.complete = 1; >+ spin_lock_init(&pmu_blink_lock); >+ init_timer(&pmu_blink_timer); >+ pmu_blink_timer.function = pmu_hd_blink_timeout; >+ >+ return 1; >+} >+ >+#endif /* CONFIG_PMU_HD_BLINK */ >+ > /* > * N.B. this can't be an initfunc, because the media-bay task can > * call ide_[un]register at any time. >@@ -462,7 +543,7 @@ > ide_hwif_t *hwif = HWIF(drive); > int result = 1; > >- disable_irq(hwif->irq); /* disable_irq_nosync ?? */ >+ disable_irq_nosync(hwif->irq); > udelay(1); > SELECT_DRIVE(drive); > SELECT_MASK(drive, 0); >@@ -945,9 +1026,12 @@ > unsigned long base, regbase; > int irq; > ide_hwif_t *hwif; >- >+#ifdef CONFIG_PMU_HD_BLINK >+ int has_blink; >+#endif > if (_machine != _MACH_Pmac) > return; >+ > pp = &atas; > rp = &removables; > p = find_devices("ATA"); >@@ -957,6 +1041,14 @@ > p = find_type_devices("ide"); > if (p == NULL) > p = find_type_devices("ata"); >+ >+ if (p == NULL) >+ return; >+ >+#ifdef CONFIG_PMU_HD_BLINK >+ has_blink = pmu_hd_blink_init(); >+#endif /* CONFIG_PMU_HD_BLINK */ >+ > /* Move removable devices such as the media-bay CDROM > on the PB3400 to the end of the list. */ > for (; p != NULL; p = nextp) { >@@ -1163,6 +1255,11 @@ > hwif->selectproc = pmac_ide_selectproc; > hwif->speedproc = pmac_ide_tune_chipset; > >+#ifdef CONFIG_PMU_HD_BLINK >+ if (has_blink) >+ hwif->led_act = pmu_hd_kick_blink; >+#endif /* CONFIG_PMU_HD_BLINK */ >+ > printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s\n", > i, model_name[pmif->kind], pmif->aapl_bus_id, > in_bay ? " (mediabay)" : ""); >@@ -1207,6 +1304,8 @@ > #ifdef CONFIG_PMAC_PBOOK > pmu_register_sleep_notifier(&idepmac_sleep_notifier); > #endif /* CONFIG_PMAC_PBOOK */ >+ >+ mdelay(IDE_WAKEUP_DELAY_MS); > } > > #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/ide/setup-pci.c linux-2.4.22-ppc-dev/drivers/ide/setup-pci.c >--- linux-2.4.22-ppc-dev.orig/drivers/ide/setup-pci.c 2003-08-27 15:17:54.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/ide/setup-pci.c 2003-08-25 23:38:12.000000000 +0200 >@@ -51,7 +51,8 @@ > { > int h; > ide_hwif_t *hwif; >- >+ int reserved = ide_reserved_hwifs(); >+ > /* > * Look for a hwif with matching io_base specified using > * parameters to ide_setup(). >@@ -90,18 +91,18 @@ > */ > if (bootable) { > for (h = 0; h < MAX_HWIFS; ++h) { >- hwif = &ide_hwifs[h]; >+ hwif = ide_hwifs + h; > if (hwif->chipset == ide_unknown) > return hwif; /* pick an unused entry */ > } > } else { >- for (h = 2; h < MAX_HWIFS; ++h) { >+ for (h = reserved; h < MAX_HWIFS; ++h) { > hwif = ide_hwifs + h; > if (hwif->chipset == ide_unknown) > return hwif; /* pick an unused entry */ > } > } >- for (h = 0; h < 2; ++h) { >+ for (h = 0; h < reserved; ++h) { > hwif = ide_hwifs + h; > if (hwif->chipset == ide_unknown) > return hwif; /* pick an unused entry */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/macintosh/Makefile linux-2.4.22-ppc-dev/drivers/macintosh/Makefile >--- linux-2.4.22-ppc-dev.orig/drivers/macintosh/Makefile 2002-11-29 00:53:13.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/macintosh/Makefile 2003-08-25 23:38:04.000000000 +0200 >@@ -35,6 +35,8 @@ > obj-$(CONFIG_INPUT_ADBHID) += adbhid.o > obj-$(CONFIG_PPC_RTC) += rtc.o > obj-$(CONFIG_ANSLCD) += ans-lcd.o >+#obj-$(CONFIG_I2C) += therm_pismo.o >+#obj-$(CONFIG_I2C) += therm_albooks.o > > obj-$(CONFIG_ADB_PMU) += via-pmu.o > obj-$(CONFIG_ADB_CUDA) += via-cuda.o >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/macintosh/macserial.c linux-2.4.22-ppc-dev/drivers/macintosh/macserial.c >--- linux-2.4.22-ppc-dev.orig/drivers/macintosh/macserial.c 2002-08-03 02:39:44.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/macintosh/macserial.c 2003-08-25 23:37:39.000000000 +0200 >@@ -59,7 +59,7 @@ > }; > #endif > >-#define SUPPORT_SERIAL_DMA >+#undef SUPPORT_SERIAL_DMA > #define MACSERIAL_VERSION "2.0" > > /* >@@ -1134,6 +1134,8 @@ > */ > static void shutdown(struct mac_serial * info) > { >+ unsigned long flags; >+ > OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line, > info->irq); > >@@ -1142,6 +1144,8 @@ > return; > } > >+ save_flags(flags); cli(); /* Disable interrupts */ >+ > if (info->has_dma) { > del_timer(&info->poll_dma_timer); > dbdma_reset(info->tx_dma); >@@ -1151,6 +1155,8 @@ > } > disable_irq(info->irq); > >+ restore_flags(flags); >+ > info->pendregs[1] = info->curregs[1] = 0; > write_zsreg(info->zs_channel, 1, 0); /* no interrupts */ > >@@ -1980,6 +1986,7 @@ > return; > } > info->flags |= ZILOG_CLOSING; >+ restore_flags(flags); > /* > * Save the termios structure, since this port may have > * separate termios for callout and dialin. >@@ -1994,11 +2001,8 @@ > */ > OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait); > tty->closing = 1; >- if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) { >- restore_flags(flags); >+ if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) > tty_wait_until_sent(tty, info->closing_wait); >- save_flags(flags); cli(); >- } > > /* > * At this point we stop accepting input. To do this, we >@@ -2017,15 +2021,10 @@ > * has completely drained. > */ > OPNDBG("waiting end of Rx...\n"); >- restore_flags(flags); > rs_wait_until_sent(tty, info->timeout); >- save_flags(flags); cli(); > } > > shutdown(info); >- /* restore flags now since shutdown() will have disabled this port's >- specific irqs */ >- restore_flags(flags); > > if (tty->driver.flush_buffer) > tty->driver.flush_buffer(tty); >@@ -2880,7 +2879,7 @@ > static int __init serial_console_setup(struct console *co, char *options) > { > struct mac_serial *info; >- int baud = 38400; >+ int baud = 57600; /*38400;*/ > int bits = 8; > int parity = 'n'; > int cflag = CREAD | HUPCL | CLOCAL; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/macintosh/therm_pismo.c linux-2.4.22-ppc-dev/drivers/macintosh/therm_pismo.c >--- linux-2.4.22-ppc-dev.orig/drivers/macintosh/therm_pismo.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/macintosh/therm_pismo.c 2003-08-25 23:37:36.000000000 +0200 >@@ -0,0 +1,269 @@ >+/* >+ * Device driver for the i2c thermostat found on some laptops >+ * >+ * Copyright (C) 2001 Benjamin Herrenschmidt >+ * >+ * Actually, there are 2 DS1775R1 on uninorth I2C busses >+ */ >+ >+#include <linux/config.h> >+#include <linux/types.h> >+#include <linux/module.h> >+#include <linux/errno.h> >+#include <linux/kernel.h> >+#include <linux/delay.h> >+#include <linux/sched.h> >+#include <linux/i2c.h> >+#include <linux/slab.h> >+#include <linux/init.h> >+#include <asm/prom.h> >+#include <asm/machdep.h> >+#include <asm/io.h> >+#include <asm/system.h> >+#include <asm/sections.h> >+ >+#define DEBUG >+ >+#define I2C_THERMOSTAT_ADDR 0x49 >+#define I2C_THERMOSTAT_ADDR2 0x48 >+#define MAX_THERMOSTATS 4 >+ >+ >+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); >+MODULE_DESCRIPTION("Driver for DS1775 thermostat on Apple laptops"); >+MODULE_LICENSE("GPL"); >+EXPORT_NO_SYMBOLS; >+ >+struct temp_range >+{ >+ u8 high; /* Start the fan */ >+ u8 low; /* Stop the fan */ >+}; >+ >+struct apple_thermal_info { >+ u8 id; /* Implementation ID */ >+ u8 fan_count; /* Number of fans */ >+ u8 thermostat_count; /* Number of thermostats */ >+ u8 unused[5]; >+ struct temp_range ranges[4]; /* Temperature ranges (may be [])*/ >+}; >+ >+struct thermostat { >+ struct i2c_client clt; >+ int th_num; >+ // more to come ? >+}; >+ >+static struct apple_thermal_info *thinfo; >+static struct thermostat* thermostats[MAX_THERMOSTATS]; >+static int therm_count; >+ >+static int attach_thermostat(struct i2c_adapter *adapter); >+static int detach_thermostat(struct i2c_client *client); >+ >+/* What is this supposed to be ? registered ? I hate >+ * magic numbers like that ... >+ */ >+#define I2C_DRIVERID_THERMOSTAT (0xDEAD) >+ >+static struct i2c_driver thermostat_driver = { >+ name: "Apple Thermostat", >+ id: I2C_DRIVERID_THERMOSTAT, >+ flags: I2C_DF_NOTIFY, >+ attach_adapter: &attach_thermostat, >+ detach_client: &detach_thermostat, >+ command: NULL, >+ inc_use: NULL, >+ dec_use: NULL >+}; >+ >+static int >+write_reg(struct thermostat* th, int reg, u8* data, int len) >+{ >+ u8 tmp[5]; >+ int rc; >+ >+ if (len > 4) >+ return -EINVAL; >+ tmp[0] = reg; >+ memcpy(&tmp[1], data, len); >+ rc = i2c_master_send(&th->clt, (const char *)tmp, len+1); >+ if (rc < 0) >+ return rc; >+ if (rc != (len+1)) >+ return -ENODEV; >+ return 0; >+} >+ >+static int >+read_reg(struct thermostat* th, int reg, u8* data, int len) >+{ >+ u8 reg_addr; >+ int rc; >+ >+ reg_addr = (u8)reg; >+ rc = i2c_master_send(&th->clt, ®_addr, 1); >+ if (rc < 0) >+ return rc; >+ if (rc != 1) >+ return -ENODEV; >+ rc = i2c_master_recv(&th->clt, (char *)data, len); >+ if (rc < 0) >+ return rc; >+ if (rc != len) >+ return -ENODEV; >+ return 0; >+} >+ >+static int >+attach_one_thermostat(struct i2c_adapter *adapter, int addr, int num) >+{ >+ struct thermostat* th; >+ int rc; >+ u16 t, tlo, thi; >+ u8 config; >+ >+ if (therm_count >= MAX_THERMOSTATS) { >+ printk(KERN_WARNING "Skipped thermostat %d (%s:%x), max count reached !\n", >+ num, adapter->name, addr); >+ return -ENODEV; >+ } >+ >+ th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL); >+ if (!th) >+ return -ENOMEM; >+ th->clt.addr = addr; >+ th->clt.adapter = adapter; >+ th->clt.driver = &thermostat_driver; >+ th->clt.flags = 0; >+ th->clt.data = (void *)therm_count; >+ th->th_num = num; >+ strcpy(th->clt.name, "thermostat"); >+ >+ rc = read_reg(th, 1, &config, 1); >+ if (rc < 0) { >+ printk(KERN_ERR "Thermostat %d (%s:%x) failed to read config !\n", >+ num, adapter->name, addr); >+ kfree(th); >+ return -ENODEV; >+ } >+ printk(KERN_INFO "Thermostat %d (%s:%x), config: %02x\n", >+ num, adapter->name, addr, config); >+ >+ rc = read_reg(th, 0, (u8 *)&t, 2); >+ if (rc < 0) { >+ printk(KERN_ERR "Thermostat %d (%s:%x) failed to read temp !\n", >+ num, adapter->name, addr); >+ kfree(th); >+ return -ENODEV; >+ } >+ printk(KERN_INFO "Thermostat %d (%s:%x), temp: %04x (about: %d degree C)\n", >+ num, adapter->name, addr, t, t>>8); >+ >+ thermostats[therm_count++] = th; >+ >+ if (i2c_attach_client(&th->clt)) { >+ printk(KERN_ERR "Thermostat %d (%s:%x), failed to attach client !\n", >+ num, adapter->name, addr); >+ thermostats[--therm_count] = NULL; >+ kfree(th); >+ return -ENODEV; >+ } >+ >+ tlo = thi = 0; >+ rc = read_reg(th, 2, (u8 *)&tlo, 2); >+ if (rc < 0) { >+ printk(KERN_WARNING "Thermostat %d (%s:%x) failed to read low threshold !\n", >+ num, adapter->name, addr); >+ } >+ rc = read_reg(th, 3, (u8 *)&thi, 2); >+ if (rc < 0) { >+ printk(KERN_WARNING "Thermostat %d (%s:%x) failed to read high threshold !\n", >+ num, adapter->name, addr); >+ } >+ printk(KERN_INFO "Thermostat %d (%s:%x), tl: %04x (%d degree C), th: %04x (%d degree C)\n", >+ num, adapter->name, addr, tlo, tlo>>8, thi, thi>>8); >+ return 0; >+} >+ >+static int >+attach_thermostat(struct i2c_adapter *adapter) >+{ >+ unsigned long bus_no; >+ int rc; >+ >+ if (strncmp(adapter->name, "uni-n", 5)) >+ return 0; >+ bus_no = simple_strtoul(adapter->name + 6, NULL, 10); >+ rc = attach_one_thermostat(adapter, I2C_THERMOSTAT_ADDR, bus_no); >+ if (!rc && thinfo->thermostat_count > 2) >+ attach_one_thermostat(adapter, I2C_THERMOSTAT_ADDR2, bus_no+2); >+ >+ return rc; >+} >+ >+static int >+detach_thermostat(struct i2c_client *client) >+{ >+ int index = (int)client->data; >+ struct thermostat* th; >+ >+ if (index >= MAX_THERMOSTATS || !thermostats[index]) { >+ printk(KERN_ERR "Invalid client in deatch_thermostat()\n"); >+ return -ENODEV; >+ } >+ th = thermostats[index]; >+ i2c_detach_client(&th->clt); >+ thermostats[index] = NULL; >+ >+ kfree(th); >+ >+ return 0; >+} >+ >+static int __init >+thermostat_init(void) >+{ >+ struct device_node* np; >+ >+ if (!machine_is_compatible("PowerBook3,1")) >+ return -ENODEV; >+ >+ np = find_devices("power-mgt"); >+ if (!np) >+ return -ENODEV; >+ thinfo = (struct apple_thermal_info *)get_property(np, "thermal-info", NULL); >+ if (!thinfo) >+ return -ENODEV; >+ >+#ifdef DEBUG >+ printk(KERN_DEBUG " Thermal Infos found :\n"); >+ printk(KERN_DEBUG " implementation id : %d\n", thinfo->id); >+ printk(KERN_DEBUG " fan_count : %d\n", thinfo->fan_count); >+ printk(KERN_DEBUG " thermostat_count : %d\n", thinfo->thermostat_count); >+ printk(KERN_DEBUG " ranges[0] : %d,%d\n", >+ thinfo->ranges[0].high, thinfo->ranges[0].low); >+ printk(KERN_DEBUG " ranges[1] : %d,%d\n", >+ thinfo->ranges[1].high, thinfo->ranges[1].low); >+ printk(KERN_DEBUG " ranges[2] : %d,%d\n", >+ thinfo->ranges[2].high, thinfo->ranges[2].low); >+ printk(KERN_DEBUG " ranges[3] : %d,%d\n", >+ thinfo->ranges[3].high, thinfo->ranges[3].low); >+#endif >+ /* Check against titaniums & ibooks.... */ >+ if (thinfo->id != 1 && thinfo->id != 2) { >+ printk(KERN_ERR "thermostat: design id %d unknown !\n", thinfo->id); >+ return -ENODEV; >+ } >+ >+ return i2c_add_driver(&thermostat_driver); >+} >+ >+static void __exit >+thermostat_exit(void) >+{ >+ i2c_del_driver(&thermostat_driver); >+} >+ >+module_init(thermostat_init); >+module_exit(thermostat_exit); >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/macintosh/via-pmu.c linux-2.4.22-ppc-dev/drivers/macintosh/via-pmu.c >--- linux-2.4.22-ppc-dev.orig/drivers/macintosh/via-pmu.c 2003-08-27 15:17:54.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/macintosh/via-pmu.c 2003-08-25 23:37:51.000000000 +0200 >@@ -64,6 +64,13 @@ > /* How many iterations between battery polls */ > #define BATTERY_POLLING_COUNT 2 > >+/* Some debugging tools */ >+#ifdef CONFIG_XMON >+//#define LIVE_DEBUG(req) ((req) && (req)->data[0] == 0x7d) >+#define LIVE_DEBUG(req) (0) >+static int whacky_debug; >+#endif /* CONFIG_XMON */ >+ > static volatile unsigned char *via; > > /* VIA registers - spaced 0x200 bytes apart */ >@@ -107,6 +114,7 @@ > intack, > reading, > reading_intr, >+ locked, > } pmu_state; > > static volatile enum int_data_state { >@@ -134,6 +142,7 @@ > static int pmu_has_adb; > static unsigned char *gpio_reg = NULL; > static int gpio_irq = -1; >+static int gpio_irq_enabled = -1; > static volatile int pmu_suspended = 0; > static spinlock_t pmu_lock; > static u8 pmu_intr_mask; >@@ -144,9 +153,11 @@ > static int sleep_in_progress; > static int can_sleep; > #endif /* CONFIG_PMAC_PBOOK */ >+static unsigned int pmu_irq_stats[11]; > > static struct proc_dir_entry *proc_pmu_root; > static struct proc_dir_entry *proc_pmu_info; >+static struct proc_dir_entry *proc_pmu_irqstats; > static struct proc_dir_entry *proc_pmu_options; > > #ifdef CONFIG_PMAC_PBOOK >@@ -185,6 +196,8 @@ > static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); > static int proc_get_info(char *page, char **start, off_t off, > int count, int *eof, void *data); >+static int proc_get_irqstats(char *page, char **start, off_t off, >+ int count, int *eof, void *data); > #ifdef CONFIG_PMAC_BACKLIGHT > static int pmu_set_backlight_level(int level, void* data); > static int pmu_set_backlight_enable(int on, int level, void* data); >@@ -206,7 +219,7 @@ > pmu_init, > pmu_send_request, > pmu_adb_autopoll, >- pmu_poll, >+ pmu_poll_adb, > pmu_adb_reset_bus > }; > #endif /* CONFIG_ADB */ >@@ -419,6 +432,7 @@ > if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) { > if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0)) > printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq); >+ gpio_irq_enabled = 1; > } > > /* Enable interrupts */ >@@ -466,6 +480,8 @@ > int i; > proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root, > proc_get_info, NULL); >+ proc_pmu_irqstats = create_proc_read_entry("interrupts", 0, proc_pmu_root, >+ proc_get_irqstats, NULL); > #ifdef CONFIG_PMAC_PBOOK > for (i=0; i<pmu_battery_count; i++) { > char title[16]; >@@ -540,8 +556,7 @@ > > /* Read PMU version */ > pmu_request(&req, NULL, 1, PMU_GET_VERSION); >- while (!req.complete) >- pmu_poll(); >+ pmu_wait_complete(&req); > if (req.reply_len > 0) > pmu_version = req.reply[0]; > >@@ -745,7 +760,7 @@ > > #endif /* CONFIG_PMAC_PBOOK */ > >-static int >+static int __pmac > proc_get_info(char *page, char **start, off_t off, > int count, int *eof, void *data) > { >@@ -762,8 +777,35 @@ > return p - page; > } > >+static int __pmac >+proc_get_irqstats(char *page, char **start, off_t off, >+ int count, int *eof, void *data) >+{ >+ int i; >+ char* p = page; >+ static const char *irq_names[] = { >+ "Total CB1 triggered events", >+ "Total GPIO1 triggered events", >+ "PC-Card eject button", >+ "Sound/Brightness button", >+ "ADB message", >+ "Battery state change", >+ "Environment interrupt", >+ "Tick timer", >+ "Ghost interrupt (zero len)", >+ "Empty interrupt (empty mask)", >+ "Max irqs in a row" >+ }; >+ >+ for (i=0; i<11; i++) { >+ p += sprintf(p, " %2u: %10u (%s)\n", >+ i, pmu_irq_stats[i], irq_names[i]); >+ } >+ return p - page; >+} >+ > #ifdef CONFIG_PMAC_PBOOK >-static int >+static int __pmac > proc_get_batt(char *page, char **start, off_t off, > int count, int *eof, void *data) > { >@@ -788,7 +830,7 @@ > } > #endif /* CONFIG_PMAC_PBOOK */ > >-static int >+static int __pmac > proc_read_options(char *page, char **start, off_t off, > int count, int *eof, void *data) > { >@@ -802,7 +844,7 @@ > return p - page; > } > >-static int >+static int __pmac > proc_write_options(struct file *file, const char *buffer, > unsigned long count, void *data) > { >@@ -843,7 +885,7 @@ > > #ifdef CONFIG_ADB > /* Send an ADB command */ >-static int __openfirmware >+static int __pmac > pmu_send_request(struct adb_request *req, int sync) > { > int i, ret; >@@ -923,7 +965,7 @@ > } > > /* Enable/disable autopolling */ >-static int __openfirmware >+static int __pmac > pmu_adb_autopoll(int devs) > { > struct adb_request req; >@@ -946,7 +988,7 @@ > } > > /* Reset the ADB bus */ >-static int __openfirmware >+static int __pmac > pmu_adb_reset_bus(void) > { > struct adb_request req; >@@ -971,8 +1013,7 @@ > printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n"); > return -EIO; > } >- while (!req.complete) >- pmu_poll(); >+ pmu_wait_complete(&req); > > if (save_autopoll != 0) > pmu_adb_autopoll(save_autopoll); >@@ -1008,7 +1049,7 @@ > return pmu_queue_request(req); > } > >-int __openfirmware >+int __pmac > pmu_queue_request(struct adb_request *req) > { > unsigned long flags; >@@ -1050,7 +1091,7 @@ > static inline void > wait_for_ack(void) > { >- /* Sightly increased the delay, I had one occurence of the message >+ /* Sightly increased the delay, I had one occurrence of the message > * reported > */ > int timeout = 4000; >@@ -1100,8 +1141,8 @@ > (*done)(req); > } > >-static void __openfirmware >-pmu_start() >+static void __pmac >+pmu_start(void) > { > struct adb_request *req; > >@@ -1122,17 +1163,32 @@ > wait_for_ack(); > /* set the shift register to shift out and send a byte */ > send_byte(req->data[0]); >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(req)) >+ xmon_printf("R"); >+ else >+ whacky_debug = 0; >+#endif /* CONFIG_XMON */ > } > > void __openfirmware >-pmu_poll() >+pmu_poll(void) >+{ >+ if (!via) >+ return; >+ if (disable_poll) >+ return; >+ via_pmu_interrupt(0, 0, 0); >+} >+ >+void __openfirmware >+pmu_poll_adb(void) > { > if (!via) > return; > if (disable_poll) > return; > /* Kicks ADB read when PMU is suspended */ >- if (pmu_suspended) > adb_int_pending = 1; > do { > via_pmu_interrupt(0, 0, 0); >@@ -1140,6 +1196,15 @@ > || req_awaiting_reply)); > } > >+void __openfirmware >+pmu_wait_complete(struct adb_request *req) >+{ >+ if (!via) >+ return; >+ while((pmu_state != idle && pmu_state != locked) || !req->complete) >+ via_pmu_interrupt(0, 0, 0); >+} >+ > /* This function loops until the PMU is idle and prevents it from > * anwsering to ADB interrupts. pmu_request can still be called. > * This is done to avoid spurrious shutdowns when we know we'll have >@@ -1164,6 +1229,8 @@ > > do { > spin_unlock_irqrestore(&pmu_lock, flags); >+ if (req_awaiting_reply) >+ adb_int_pending = 1; > via_pmu_interrupt(0, 0, 0); > spin_lock_irqsave(&pmu_lock, flags); > if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { >@@ -1174,7 +1241,7 @@ > pmu_poll(); > #else /* SUSPEND_USES_PMU */ > if (gpio_irq >= 0) >- disable_irq(gpio_irq); >+ disable_irq_nosync(gpio_irq); > out_8(&via[IER], CB1_INT | IER_CLR); > spin_unlock_irqrestore(&pmu_lock, flags); > #endif /* SUSPEND_USES_PMU */ >@@ -1213,19 +1280,50 @@ > } > > /* Interrupt data could be the result data from an ADB cmd */ >-static void __openfirmware >+static void __pmac > pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) > { >+ unsigned char ints, pirq; >+ int i = 0; >+ > asleep = 0; > if (drop_interrupts || len < 1) { > adb_int_pending = 0; >+ pmu_irq_stats[8]++; >+ return; >+ } >+ >+ /* Get PMU interrupt mask */ >+ ints = data[0]; >+ >+ /* Record zero interrupts for stats */ >+ if (ints == 0) >+ pmu_irq_stats[9]++; >+ >+ /* Hack to deal with ADB autopoll flag */ >+ if (ints & PMU_INT_ADB) >+ ints &= ~(PMU_INT_ADB_AUTO | PMU_INT_AUTO_SRQ_POLL); >+ >+next: >+ >+ if (ints == 0) { >+ if (i > pmu_irq_stats[10]) >+ pmu_irq_stats[10] = i; > return; > } >+ >+ for (pirq = 0; pirq < 8; pirq++) >+ if (ints & (1 << pirq)) >+ break; >+ pmu_irq_stats[pirq]++; >+ i++; >+ ints &= ~(1 << pirq); >+ > /* Note: for some reason, we get an interrupt with len=1, > * data[0]==0 after each normal ADB interrupt, at least > * on the Pismo. Still investigating... --BenH > */ >- if (data[0] & PMU_INT_ADB) { >+ if ((1 << pirq) & PMU_INT_ADB) { > if ((data[0] & PMU_INT_ADB_AUTO) == 0) { > struct adb_request *req = req_awaiting_reply; > if (req == 0) { >@@ -1263,32 +1361,40 @@ > adb_input(data+1, len-1, regs, 1); > #endif /* CONFIG_ADB */ > } >- } else { >+ } > /* Sound/brightness button pressed */ >- if ((data[0] & PMU_INT_SNDBRT) && len == 3) { >+ else if ((1 << pirq) & PMU_INT_SNDBRT) { > #ifdef CONFIG_PMAC_BACKLIGHT >+ if (len == 3) > #ifdef CONFIG_INPUT_ADBHID > if (!disable_kernel_backlight) > #endif /* CONFIG_INPUT_ADBHID */ > set_backlight_level(data[1] >> 4); > #endif /* CONFIG_PMAC_BACKLIGHT */ > } >+ /* Tick interrupt */ >+ else if ((1 << pirq) & PMU_INT_TICK) { > #ifdef CONFIG_PMAC_PBOOK > /* Environement or tick interrupt, query batteries */ >- if (pmu_battery_count && (data[0] & PMU_INT_TICK)) { >+ if (pmu_battery_count) { > if ((--query_batt_timer) == 0) { > query_battery_state(); > query_batt_timer = BATTERY_POLLING_COUNT; > } >- } else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT)) >+ } >+ } >+ else if ((1 << pirq) & PMU_INT_ENVIRONMENT) { >+ if (pmu_battery_count) > query_battery_state(); >- if (data[0]) > pmu_pass_intr(data, len); >+ } else >+ pmu_pass_intr(data, len); >+ > #endif /* CONFIG_PMAC_PBOOK */ >- } >+ goto next; > } > >-static struct adb_request* __openfirmware >+static struct adb_request* __pmac > pmu_sr_intr(struct pt_regs *regs) > { > struct adb_request *req; >@@ -1315,17 +1421,29 @@ > case sending: > req = current_req; > if (data_len < 0) { >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(req)) >+ xmon_printf("s"); >+#endif /* CONFIG_XMON */ > data_len = req->nbytes - 1; > send_byte(data_len); > break; > } > if (data_index <= data_len) { >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(req)) >+ xmon_printf("S"); >+#endif /* CONFIG_XMON */ > send_byte(req->data[data_index++]); > break; > } > req->sent = 1; > data_len = pmu_data_len[req->data[0]][1]; > if (data_len == 0) { >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(req)) >+ xmon_printf("D"); >+#endif /* CONFIG_XMON */ > pmu_state = idle; > current_req = req->next; > if (req->reply_expected) >@@ -1333,6 +1451,10 @@ > else > return req; > } else { >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(req)) >+ xmon_printf("-"); >+#endif /* CONFIG_XMON */ > pmu_state = reading; > data_index = 0; > reply_ptr = req->reply + req->reply_len; >@@ -1346,15 +1468,27 @@ > pmu_state = reading_intr; > reply_ptr = interrupt_data[int_data_last]; > recv_byte(); >+ if (gpio_irq >= 0 && !gpio_irq_enabled) { >+ enable_irq(gpio_irq); >+ gpio_irq_enabled = 1; >+ } > break; > > case reading: > case reading_intr: > if (data_len == -1) { >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(current_req)) >+ xmon_printf("r"); >+#endif /* CONFIG_XMON */ > data_len = bite; > if (bite > 32) > printk(KERN_ERR "PMU: bad reply len %d\n", bite); > } else if (data_index < 32) { >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(current_req)) >+ xmon_printf("R"); >+#endif /* CONFIG_XMON */ > reply_ptr[data_index++] = bite; > } > if (data_index < data_len) { >@@ -1362,14 +1496,28 @@ > break; > } > >+#ifdef CONFIG_XMON >+ if (LIVE_DEBUG(current_req)) { >+ whacky_debug = 1; >+ xmon_printf("D"); >+ } >+#endif /* CONFIG_XMON */ > if (pmu_state == reading_intr) { > pmu_state = idle; > int_data_state[int_data_last] = int_data_ready; > interrupt_data_len[int_data_last] = data_len; > } else { > req = current_req; >+ /* >+ * For PMU sleep and freq change requests, we lock the >+ * PMU until it's explicitely unlocked. This avoids any >+ * spurrious event polling getting in >+ */ > current_req = req->next; > req->reply_len += data_index; >+ if (req->data[0] == PMU_SLEEP || req->data[0] == PMU_CPU_SPEED) >+ pmu_state = locked; >+ else > pmu_state = idle; > return req; > } >@@ -1399,6 +1547,10 @@ > intr = in_8(&via[IFR]) & (SR_INT | CB1_INT); > if (intr == 0) > break; >+#ifdef CONFIG_XMON >+ if (whacky_debug) >+ xmon_printf("|%02x|", intr); >+#endif /* CONFIG_XMON */ > if (++nloop > 1000) { > printk(KERN_DEBUG "PMU: stuck in intr loop, " > "intr=%x, ier=%x pmu_state=%d\n", >@@ -1406,8 +1558,10 @@ > break; > } > out_8(&via[IFR], intr); >- if (intr & CB1_INT) >+ if (intr & CB1_INT) { > adb_int_pending = 1; >+ pmu_irq_stats[0]++; >+ } > if (intr & SR_INT) { > req = pmu_sr_intr(regs); > if (req) >@@ -1418,6 +1572,10 @@ > recheck: > if (pmu_state == idle) { > if (adb_int_pending) { >+#ifdef CONFIG_XMON >+ if (whacky_debug) >+ xmon_printf("!A!"); >+#endif /* CONFIG_XMON */ > if (int_data_state[0] == int_data_empty) > int_data_last = 0; > else if (int_data_state[1] == int_data_empty) >@@ -1432,11 +1590,10 @@ > wait_for_ack(); > send_byte(PMU_INT_ACK); > adb_int_pending = 0; >-no_free_slot: >- ; > } else if (current_req) > pmu_start(); > } >+no_free_slot: > /* Mark the oldest buffer for flushing */ > if (int_data_state[!int_data_last] == int_data_ready) { > int_data_state[!int_data_last] = int_data_flush; >@@ -1465,17 +1622,39 @@ > } > } > >+void __pmac >+pmu_unlock(void) >+{ >+ unsigned long flags; >+ >+ spin_lock_irqsave(&pmu_lock, flags); >+ if (pmu_state == locked) >+ pmu_state = idle; >+ adb_int_pending = 1; >+ spin_unlock_irqrestore(&pmu_lock, flags); >+} >+ >+ > static void __openfirmware > gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) > { >+ unsigned long flags; >+ > if ((in_8(gpio_reg + 0x9) & 0x02) == 0) { >+ spin_lock_irqsave(&pmu_lock, flags); >+ if (gpio_irq_enabled > 0) { >+ disable_irq_nosync(gpio_irq); >+ gpio_irq_enabled = 0; >+ } >+ pmu_irq_stats[1]++; > adb_int_pending = 1; >+ spin_unlock_irqrestore(&pmu_lock, flags); > via_pmu_interrupt(0, 0, 0); > } > } > > #ifdef CONFIG_PMAC_BACKLIGHT >-static int backlight_to_bright[] = { >+static int backlight_to_bright[] __pmacdata = { > 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, > 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e > }; >@@ -1491,13 +1670,11 @@ > if (on) { > pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, > backlight_to_bright[level]); >- while (!req.complete) >- pmu_poll(); >+ pmu_wait_complete(&req); > } > pmu_request(&req, NULL, 2, PMU_POWER_CTRL, > PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); >- while (!req.complete) >- pmu_poll(); >+ pmu_wait_complete(&req); > > return 0; > } >@@ -1521,7 +1698,7 @@ > } > #endif /* CONFIG_PMAC_BACKLIGHT */ > >-void __openfirmware >+void __pmac > pmu_enable_irled(int on) > { > struct adb_request req; >@@ -1533,11 +1710,10 @@ > > pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED | > (on ? PMU_POW_ON : PMU_POW_OFF)); >- while (!req.complete) >- pmu_poll(); >+ pmu_wait_complete(&req); > } > >-void __openfirmware >+void __pmac > pmu_restart(void) > { > struct adb_request req; >@@ -1554,13 +1730,12 @@ > } > > pmu_request(&req, NULL, 1, PMU_RESET); >- while(!req.complete || (pmu_state != idle)) >- pmu_poll(); >+ pmu_wait_complete(&req); > for (;;) > ; > } > >-void __openfirmware >+void __pmac > pmu_shutdown(void) > { > struct adb_request req; >@@ -1572,14 +1747,12 @@ > if (pmu_kind != PMU_KEYLARGO_BASED) { > pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | > PMU_INT_TICK ); >- while(!req.complete) >- pmu_poll(); >+ pmu_wait_complete(&req); > } > > pmu_request(&req, NULL, 5, PMU_SHUTDOWN, > 'M', 'A', 'T', 'T'); >- while(!req.complete || (pmu_state != idle)) >- pmu_poll(); >+ pmu_wait_complete(&req); > for (;;) > ; > } >@@ -2245,6 +2418,7 @@ > set_context(current->active_mm->context, current->active_mm->pgd); > > /* Power things up */ >+ pmu_unlock(); > pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); > while (!req.complete) > pmu_poll(); >@@ -2410,6 +2584,7 @@ > //pbook_pci_restore(); > > #ifdef DEBUG_SLEEP >+ pmu_unlock(); > pmu_blink(2); > #endif > /* Restore L2 cache */ >@@ -2423,6 +2598,7 @@ > set_context(current->active_mm->context, current->active_mm->pgd); > > /* Tell PMU we are ready */ >+ pmu_unlock(); > pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); > while (!req.complete) > pmu_poll(); >@@ -2555,10 +2731,7 @@ > out_be32(mem_ctrl_sleep, 0x3f); > pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); > pbook_pci_restore(); >- >- /* wait for the PMU interrupt sequence to complete */ >- while (asleep) >- mb(); >+ pmu_unlock(); > > /* reenable interrupts */ > pmac_sleep_restore_intrs(); >@@ -2921,8 +3094,11 @@ > > EXPORT_SYMBOL(pmu_request); > EXPORT_SYMBOL(pmu_poll); >+EXPORT_SYMBOL(pmu_poll_adb); >+EXPORT_SYMBOL(pmu_wait_complete); > EXPORT_SYMBOL(pmu_suspend); > EXPORT_SYMBOL(pmu_resume); >+EXPORT_SYMBOL(pmu_unlock); > EXPORT_SYMBOL(pmu_i2c_combined_read); > EXPORT_SYMBOL(pmu_i2c_stdsub_write); > EXPORT_SYMBOL(pmu_i2c_simple_read); >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/Makefile linux-2.4.22-ppc-dev/drivers/net/Makefile >--- linux-2.4.22-ppc-dev.orig/drivers/net/Makefile 2003-08-27 15:17:54.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/Makefile 2003-08-25 23:37:55.000000000 +0200 >@@ -17,7 +17,7 @@ > > export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o \ > ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \ >- net_init.o mii.o >+ net_init.o mii.o sungem_phy.o > list-multi := rcpci.o > rcpci-objs := rcpci45.o rclanmtl.o > >@@ -67,7 +67,7 @@ > obj-$(CONFIG_SUNQE) += sunqe.o > obj-$(CONFIG_SUNBMAC) += sunbmac.o > obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o >-obj-$(CONFIG_SUNGEM) += sungem.o >+obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o > > obj-$(CONFIG_MACE) += mace.o > obj-$(CONFIG_BMAC) += bmac.o >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/irda/irda-usb.c linux-2.4.22-ppc-dev/drivers/net/irda/irda-usb.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/irda/irda-usb.c 2003-08-27 15:17:55.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/irda/irda-usb.c 2003-08-25 23:37:36.000000000 +0200 >@@ -1386,6 +1386,9 @@ > WARNING("usb-irda: bad class_descriptor type\n"); > } > else { >+ le16_to_cpus (&(desc->wBaudRate)); >+ le16_to_cpus (&(desc->bcdSpecRevision)); >+ > #ifdef IU_DUMP_CLASS_DESC > irda_usb_dump_class_desc(desc); > #endif /* IU_DUMP_CLASS_DESC */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/ne2k-pci.c linux-2.4.22-ppc-dev/drivers/net/ne2k-pci.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/ne2k-pci.c 2003-08-27 15:17:55.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/ne2k-pci.c 2003-08-25 23:37:52.000000000 +0200 >@@ -69,8 +69,6 @@ > #if defined(__powerpc__) > #define inl_le(addr) le32_to_cpu(inl(addr)) > #define inw_le(addr) le16_to_cpu(inw(addr)) >-#define insl insl_ns >-#define outsl outsl_ns > #endif > > #define PFX DRV_NAME ": " >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/pcnet32.c linux-2.4.22-ppc-dev/drivers/net/pcnet32.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/pcnet32.c 2003-08-27 15:17:55.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/pcnet32.c 2003-08-25 23:37:44.000000000 +0200 >@@ -569,7 +569,7 @@ > break; > case 0x2625: > chipname = "PCnet/FAST III 79C973"; /* PCI */ >- fdx = 1; mii = 1; >+ fdx = 1; mii = 1; fset = 1; > break; > case 0x2626: > chipname = "PCnet/Home 79C978"; /* PCI */ >@@ -612,6 +612,7 @@ > > if(fset) > { >+ printk(KERN_INFO PFX "Activating Tx error recovery on %s\n", chipname); > a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); > a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); > dxsuflo = 1; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/sungem.c linux-2.4.22-ppc-dev/drivers/net/sungem.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/sungem.c 2003-08-27 15:17:56.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/sungem.c 2003-08-25 23:38:01.000000000 +0200 >@@ -10,10 +10,6 @@ > * - Get rid of all those nasty mdelay's and replace them > * with schedule_timeout. > * - Implement WOL >- * - Currently, forced Gb mode is only supported on bcm54xx >- * PHY for which I use the SPD2 bit of the control register. >- * On m1011 PHY, I can't force as I don't have the specs, but >- * I can at least detect gigabit with autoneg. > */ > > #include <linux/config.h> >@@ -63,12 +59,20 @@ > #include <asm/pmac_feature.h> > #endif > >+#include "sungem_phy.h" > #include "sungem.h" > >+/* Stripping FCS is causing problems, disabled for now */ >+#undef STRIP_FCS >+ > #define DEFAULT_MSG (NETIF_MSG_DRV | \ > NETIF_MSG_PROBE | \ > NETIF_MSG_LINK) > >+#define ADVERTISE_MASK (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ >+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ >+ SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) >+ > #define DRV_NAME "sungem" > #define DRV_VERSION "0.97" > #define DRV_RELDATE "3/20/02" >@@ -81,24 +85,6 @@ > MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver"); > MODULE_LICENSE("GPL"); > >-MODULE_PARM(gem_debug, "i"); >-MODULE_PARM_DESC(gem_debug, "bitmapped message enable number"); >-MODULE_PARM(link_mode, "i"); >-MODULE_PARM_DESC(link_mode, "default link mode"); >- >-int gem_debug = -1; >-static int link_mode; >- >-static u16 link_modes[] __devinitdata = { >- BMCR_ANENABLE, /* 0 : autoneg */ >- 0, /* 1 : 10bt half duplex */ >- BMCR_SPEED100, /* 2 : 100bt half duplex */ >- BMCR_SPD2, /* bcm54xx only */ /* 3 : 1000bt half duplex */ >- BMCR_FULLDPLX, /* 4 : 10bt full duplex */ >- BMCR_SPEED100|BMCR_FULLDPLX, /* 5 : 100bt full duplex */ >- BMCR_SPD2|BMCR_FULLDPLX /* 6 : 1000bt full duplex */ >-}; >- > #define GEM_MODULE_NAME "gem" > #define PFX GEM_MODULE_NAME ": " > >@@ -119,12 +105,14 @@ > PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, > { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, >+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC2, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, > {0, } > }; > > MODULE_DEVICE_TABLE(pci, gem_pci_tbl); > >-static u16 __phy_read(struct gem *gp, int reg, int phy_addr) >+static u16 __phy_read(struct gem *gp, int phy_addr, int reg) > { > u32 cmd; > int limit = 10000; >@@ -150,12 +138,18 @@ > return cmd & MIF_FRAME_DATA; > } > >+static inline int _phy_read(struct net_device *dev, int mii_id, int reg) >+{ >+ struct gem *gp = dev->priv; >+ return __phy_read(gp, mii_id, reg); >+} >+ > static inline u16 phy_read(struct gem *gp, int reg) > { >- return __phy_read(gp, reg, gp->mii_phy_addr); >+ return __phy_read(gp, gp->mii_phy_addr, reg); > } > >-static void __phy_write(struct gem *gp, int reg, u16 val, int phy_addr) >+static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val) > { > u32 cmd; > int limit = 10000; >@@ -177,9 +171,15 @@ > } > } > >+static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val) >+{ >+ struct gem *gp = dev->priv; >+ __phy_write(gp, mii_id, reg, val & 0xffff); >+} >+ > static inline void phy_write(struct gem *gp, int reg, u16 val) > { >- __phy_write(gp, reg, val, gp->mii_phy_addr); >+ __phy_write(gp, gp->mii_phy_addr, reg, val); > } > > static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) >@@ -228,10 +228,11 @@ > if (pcs_miistat & PCS_MIISTAT_LS) { > printk(KERN_INFO "%s: PCS link is now up.\n", > dev->name); >+ netif_carrier_on(gp->dev); > } else { > printk(KERN_INFO "%s: PCS link is now down.\n", > dev->name); >- >+ netif_carrier_off(gp->dev); > /* If this happens and the link timer is not running, > * reset so we re-negotiate. > */ >@@ -359,6 +360,7 @@ > > rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); > } >+ mb(); > gp->rx_new = gp->rx_old = 0; > > /* Now we must reprogram the rest of RX unit. */ >@@ -400,6 +402,10 @@ > gp->dev->name, rxmac_stat); > > if (rxmac_stat & MAC_RXSTAT_OFLW) { >+ u32 smac = readl(gp->regs + MAC_SMACHINE); >+ >+ printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n", >+ dev->name, smac); > gp->net_stats.rx_over_errors++; > gp->net_stats.rx_fifo_errors++; > >@@ -667,6 +673,7 @@ > count = 0; > } > } >+ mb(); > if (kick >= 0) > writel(kick, gp->regs + RXDMA_KICK); > } >@@ -893,7 +900,7 @@ > /* We must give this initial chunk to the device last. > * Otherwise we could race with the device. > */ >- first_len = skb->len - skb->data_len; >+ first_len = skb_headlen(skb); > first_mapping = pci_map_page(gp->pdev, virt_to_page(skb->data), > ((unsigned long) skb->data & ~PAGE_MASK), > first_len, PCI_DMA_TODEVICE); >@@ -936,6 +943,7 @@ > if (netif_msg_tx_queued(gp)) > printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", > dev->name, entry, skb->len); >+ mb(); > writel(gp->tx_new, gp->regs + TXDMA_KICK); > spin_unlock_irq(&gp->lock); > >@@ -1003,7 +1011,7 @@ > } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST)); > > if (limit <= 0) >- printk(KERN_ERR "gem: SW reset is ghetto.\n"); >+ printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); > } > > /* Must be invoked under gp->lock. */ >@@ -1030,136 +1038,118 @@ > > } > >-/* Link modes of the BCM5400 PHY */ >-static int phy_BCM5400_link_table[8][3] = { >- { 0, 0, 0 }, /* No link */ >- { 0, 0, 0 }, /* 10BT Half Duplex */ >- { 1, 0, 0 }, /* 10BT Full Duplex */ >- { 0, 1, 0 }, /* 100BT Half Duplex */ >- { 0, 1, 0 }, /* 100BT Half Duplex */ >- { 1, 1, 0 }, /* 100BT Full Duplex*/ >- { 1, 0, 1 }, /* 1000BT */ >- { 1, 0, 1 }, /* 1000BT */ >-}; > > /* Must be invoked under gp->lock. */ >+// XXX dbl check what that function should do when called on PCS PHY > static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) > { >- u16 ctl; >+ u32 advertise, features; >+ int autoneg; >+ int speed; >+ int duplex; >+ >+ if (gp->phy_type != phy_mii_mdio0 && >+ gp->phy_type != phy_mii_mdio1) >+ goto non_mii; >+ >+ /* Setup advertise */ >+ if (found_mii_phy(gp)) >+ features = gp->phy_mii.def->features; >+ else >+ features = 0; >+ >+ advertise = features & ADVERTISE_MASK; >+ if (gp->phy_mii.advertising != 0) >+ advertise &= gp->phy_mii.advertising; >+ >+ autoneg = gp->want_autoneg; >+ speed = gp->phy_mii.speed; >+ duplex = gp->phy_mii.duplex; > > /* Setup link parameters */ > if (!ep) > goto start_aneg; > if (ep->autoneg == AUTONEG_ENABLE) { >- /* TODO: parse ep->advertising */ >- gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL); >- gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL); >- /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ >- gp->link_cntl = BMCR_ANENABLE; >+ advertise = ep->advertising; >+ autoneg = 1; > } else { >- gp->link_cntl = 0; >- if (ep->speed == SPEED_100) >- gp->link_cntl |= BMCR_SPEED100; >- else if (ep->speed == SPEED_1000 && gp->gigabit_capable) >- /* Hrm... check if this is right... */ >- gp->link_cntl |= BMCR_SPD2; >- if (ep->duplex == DUPLEX_FULL) >- gp->link_cntl |= BMCR_FULLDPLX; >+ autoneg = 0; >+ speed = ep->speed; >+ duplex = ep->duplex; > } > > start_aneg: >- if (!gp->hw_running) >+ /* Sanitize settings based on PHY capabilities */ >+ if ((features & SUPPORTED_Autoneg) == 0) >+ autoneg = 0; >+ if (speed == SPEED_1000 && >+ !(features & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full))) >+ speed = SPEED_100; >+ if (speed == SPEED_100 && >+ !(features & (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full))) >+ speed = SPEED_10; >+ if (duplex == DUPLEX_FULL && >+ !(features & (SUPPORTED_1000baseT_Full | >+ SUPPORTED_100baseT_Full | >+ SUPPORTED_10baseT_Full))) >+ duplex = DUPLEX_HALF; >+ if (speed == 0) >+ speed = SPEED_10; >+ >+ /* If HW is down, we don't try to actually setup the PHY, we >+ * just store the settings >+ */ >+ if (!gp->hw_running) { >+ gp->phy_mii.autoneg = gp->want_autoneg = autoneg; >+ gp->phy_mii.speed = speed; >+ gp->phy_mii.duplex = duplex; > return; >+ } > > /* Configure PHY & start aneg */ >- ctl = phy_read(gp, MII_BMCR); >- ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); >- ctl |= gp->link_cntl; >- if (ctl & BMCR_ANENABLE) { >- ctl |= BMCR_ANRESTART; >+ gp->want_autoneg = autoneg; >+ if (autoneg) { >+ if (found_mii_phy(gp)) >+ gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, advertise); > gp->lstate = link_aneg; > } else { >+ if (found_mii_phy(gp)) >+ gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, speed, duplex); > gp->lstate = link_force_ok; > } >- phy_write(gp, MII_BMCR, ctl); > >+non_mii: > gp->timer_ticks = 0; > mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); > } > >-/* Must be invoked under gp->lock. */ >-static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause) >-{ >- u32 val; >- >- *fd = 0; >- *spd = 10; >- *pause = 0; >- >- if (gp->phy_mod == phymod_bcm5400 || >- gp->phy_mod == phymod_bcm5401 || >- gp->phy_mod == phymod_bcm5411) { >- int link_mode; >- >- val = phy_read(gp, MII_BCM5400_AUXSTATUS); >- link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> >- MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); >- *fd = phy_BCM5400_link_table[link_mode][0]; >- *spd = phy_BCM5400_link_table[link_mode][2] ? >- 1000 : >- (phy_BCM5400_link_table[link_mode][1] ? 100 : 10); >- val = phy_read(gp, MII_LPA); >- if (val & LPA_PAUSE) >- *pause = 1; >- } else { >- val = phy_read(gp, MII_LPA); >- >- if (val & (LPA_10FULL | LPA_100FULL)) >- *fd = 1; >- if (val & (LPA_100FULL | LPA_100HALF)) >- *spd = 100; >- >- if (gp->phy_mod == phymod_m1011) { >- val = phy_read(gp, 0x0a); >- if (val & 0xc00) >- *spd = 1000; >- if (val & 0x800) >- *fd = 1; >- } >- } >-} >- > /* A link-up condition has occurred, initialize and enable the > * rest of the chip. > * > * Must be invoked under gp->lock. > */ >-static void gem_set_link_modes(struct gem *gp) >+static int gem_set_link_modes(struct gem *gp) > { > u32 val; > int full_duplex, speed, pause; > > full_duplex = 0; >- speed = 10; >+ speed = SPEED_10; > pause = 0; > >- if (gp->phy_type == phy_mii_mdio0 || >- gp->phy_type == phy_mii_mdio1) { >- val = phy_read(gp, MII_BMCR); >- if (val & BMCR_ANENABLE) >- gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); >- else { >- if (val & BMCR_FULLDPLX) >- full_duplex = 1; >- if (val & BMCR_SPEED100) >- speed = 100; >- } >- } else { >+ if (found_mii_phy(gp)) { >+ if (gp->phy_mii.def->ops->read_link(&gp->phy_mii)) >+ return 1; >+ full_duplex = (gp->phy_mii.duplex == DUPLEX_FULL); >+ speed = gp->phy_mii.speed; >+ pause = gp->phy_mii.pause; >+ } else if (gp->phy_type == phy_serialink || >+ gp->phy_type == phy_serdes) { > u32 pcs_lpa = readl(gp->regs + PCS_MIILP); > > if (pcs_lpa & PCS_MIIADV_FD) > full_duplex = 1; >- speed = 1000; >+ speed = SPEED_1000; > } > > if (netif_msg_link(gp)) >@@ -1183,7 +1173,7 @@ > val |= MAC_XIFCFG_FLED; > } > >- if (speed == 1000) >+ if (speed == SPEED_1000) > val |= (MAC_XIFCFG_GMII); > > writel(val, gp->regs + MAC_XIFCFG); >@@ -1191,7 +1181,7 @@ > /* If gigabit and half-duplex, enable carrier extension > * mode. Else, disable it. > */ >- if (speed == 1000 && !full_duplex) { >+ if (speed == SPEED_1000 && !full_duplex) { > val = readl(gp->regs + MAC_TXCFG); > writel(val | MAC_TXCFG_TCE, gp->regs + MAC_TXCFG); > >@@ -1239,50 +1229,51 @@ > writel(val, gp->regs + MAC_MCCFG); > > gem_start_dma(gp); >+ >+ return 0; > } > > /* Must be invoked under gp->lock. */ > static int gem_mdio_link_not_up(struct gem *gp) > { >- u16 val; >- >- if (gp->lstate == link_force_ret) { >+ switch (gp->lstate) { >+ case link_force_ret: > if (netif_msg_link(gp)) > printk(KERN_INFO "%s: Autoneg failed again, keeping" > " forced mode\n", gp->dev->name); >- phy_write(gp, MII_BMCR, gp->link_fcntl); >+ gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, >+ gp->last_forced_speed, DUPLEX_HALF); > gp->timer_ticks = 5; > gp->lstate = link_force_ok; >- } else if (gp->lstate == link_aneg) { >- val = phy_read(gp, MII_BMCR); >- >+ return 0; >+ case link_aneg: > if (netif_msg_link(gp)) > printk(KERN_INFO "%s: switching to forced 100bt\n", > gp->dev->name); > /* Try forced modes. */ >- val &= ~(BMCR_ANRESTART | BMCR_ANENABLE); >- val &= ~(BMCR_FULLDPLX); >- val |= BMCR_SPEED100; >- phy_write(gp, MII_BMCR, val); >+ gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_100, >+ DUPLEX_HALF); > gp->timer_ticks = 5; > gp->lstate = link_force_try; >- } else { >+ return 0; >+ case link_force_try: > /* Downgrade from 100 to 10 Mbps if necessary. > * If already at 10Mbps, warn user about the > * situation every 10 ticks. > */ >- val = phy_read(gp, MII_BMCR); >- if (val & BMCR_SPEED100) { >- val &= ~BMCR_SPEED100; >- phy_write(gp, MII_BMCR, val); >+ if (gp->phy_mii.speed == SPEED_100) { >+ gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_10, >+ DUPLEX_HALF); > gp->timer_ticks = 5; > if (netif_msg_link(gp)) > printk(KERN_INFO "%s: switching to forced 10bt\n", > gp->dev->name); >+ return 0; > } else > return 1; >+ default: >+ return 0; > } >- return 0; > } > > static void gem_init_rings(struct gem *); >@@ -1322,7 +1313,8 @@ > static void gem_link_timer(unsigned long data) > { > struct gem *gp = (struct gem *) data; >- >+ int restart_aneg = 0; >+ > if (!gp->hw_running) > return; > >@@ -1334,62 +1326,8 @@ > if (gp->reset_task_pending) > goto restart; > >- if (gp->phy_type == phy_mii_mdio0 || >- gp->phy_type == phy_mii_mdio1) { >- u16 val = phy_read(gp, MII_BMSR); >- u16 cntl = phy_read(gp, MII_BMCR); >- int up; >- >- /* When using autoneg, we really wait for ANEGCOMPLETE or we may >- * get a "transcient" incorrect link state >- */ >- if (cntl & BMCR_ANENABLE) >- up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS); >- else >- up = (val & BMSR_LSTATUS) != 0; >- if (up) { >- /* Ok, here we got a link. If we had it due to a forced >- * fallback, and we were configured for autoneg, we do >- * retry a short autoneg pass. If you know your hub is >- * broken, use ethtool ;) >- */ >- if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) { >- gp->lstate = link_force_ret; >- gp->link_fcntl = phy_read(gp, MII_BMCR); >- gp->timer_ticks = 5; >- if (netif_msg_link(gp)) >- printk(KERN_INFO "%s: Got link after fallback, retrying" >- " autoneg once...\n", gp->dev->name); >- phy_write(gp, MII_BMCR, >- gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART); >- } else if (gp->lstate != link_up) { >- gp->lstate = link_up; >- if (gp->opened) >- gem_set_link_modes(gp); >- } >- } else { >- int restart = 0; >- >- /* If the link was previously up, we restart the >- * whole process >- */ >- if (gp->lstate == link_up) { >- gp->lstate = link_down; >- if (netif_msg_link(gp)) >- printk(KERN_INFO "%s: Link down\n", >- gp->dev->name); >- gp->reset_task_pending = 2; >- schedule_task(&gp->reset_task); >- restart = 1; >- } else if (++gp->timer_ticks > 10) >- restart = gem_mdio_link_not_up(gp); >- >- if (restart) { >- gem_begin_auto_negotiation(gp, NULL); >- goto out_unlock; >- } >- } >- } else { >+ if (gp->phy_type == phy_serialink || >+ gp->phy_type == phy_serdes) { > u32 val = readl(gp->regs + PCS_MIISTAT); > > if (!(val & PCS_MIISTAT_LS)) >@@ -1397,11 +1335,56 @@ > > if ((val & PCS_MIISTAT_LS) != 0) { > gp->lstate = link_up; >+ netif_carrier_on(gp->dev); > if (gp->opened) >- gem_set_link_modes(gp); >+ (void)gem_set_link_modes(gp); > } >+ goto restart; >+ } >+ if (found_mii_phy(gp) && gp->phy_mii.def->ops->poll_link(&gp->phy_mii)) { >+ /* Ok, here we got a link. If we had it due to a forced >+ * fallback, and we were configured for autoneg, we do >+ * retry a short autoneg pass. If you know your hub is >+ * broken, use ethtool ;) >+ */ >+ if (gp->lstate == link_force_try && gp->want_autoneg) { >+ gp->lstate = link_force_ret; >+ gp->last_forced_speed = gp->phy_mii.speed; >+ gp->timer_ticks = 5; >+ if (netif_msg_link(gp)) >+ printk(KERN_INFO "%s: Got link after fallback, retrying" >+ " autoneg once...\n", gp->dev->name); >+ gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising); >+ } else if (gp->lstate != link_up) { >+ gp->lstate = link_up; >+ netif_carrier_on(gp->dev); >+ if (gp->opened && gem_set_link_modes(gp)) >+ restart_aneg = 1; >+ } >+ } else { >+ /* If the link was previously up, we restart the >+ * whole process >+ */ >+ if (gp->lstate == link_up) { >+ gp->lstate = link_down; >+ if (netif_msg_link(gp)) >+ printk(KERN_INFO "%s: Link down\n", >+ gp->dev->name); >+ netif_carrier_off(gp->dev); >+ gp->reset_task_pending = 2; >+ schedule_task(&gp->reset_task); >+ restart_aneg = 1; >+ } else if (++gp->timer_ticks > 10) { >+ if (found_mii_phy(gp)) >+ restart_aneg = gem_mdio_link_not_up(gp); >+ else >+ restart_aneg = 1; >+ } >+ } >+ if (restart_aneg) { >+ gem_begin_auto_negotiation(gp, NULL); >+ goto out_unlock; > } >- > restart: > mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); > out_unlock: >@@ -1501,153 +1484,14 @@ > txd->control_word = 0; > txd->buffer = 0; > } >-} >- >-/* Must be invoked under gp->lock. */ >-static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr) >-{ >- u16 val; >- int limit = 10000; >- >- val = __phy_read(gp, MII_BMCR, phy_addr); >- val &= ~BMCR_ISOLATE; >- val |= BMCR_RESET; >- __phy_write(gp, MII_BMCR, val, phy_addr); >- >- udelay(100); >- >- while (limit--) { >- val = __phy_read(gp, MII_BMCR, phy_addr); >- if ((val & BMCR_RESET) == 0) >- break; >- udelay(10); >- } >- if ((val & BMCR_ISOLATE) && limit > 0) >- __phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr); >- >- return (limit <= 0); >-} >- >-/* Must be invoked under gp->lock. */ >-static void gem_init_bcm5201_phy(struct gem *gp) >-{ >- u16 data; >- >- data = phy_read(gp, MII_BCM5201_MULTIPHY); >- data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE; >- phy_write(gp, MII_BCM5201_MULTIPHY, data); >-} >- >-/* Must be invoked under gp->lock. */ >-static void gem_init_bcm5400_phy(struct gem *gp) >-{ >- u16 data; >- >- /* Configure for gigabit full duplex */ >- data = phy_read(gp, MII_BCM5400_AUXCONTROL); >- data |= MII_BCM5400_AUXCONTROL_PWR10BASET; >- phy_write(gp, MII_BCM5400_AUXCONTROL, data); >- >- data = phy_read(gp, MII_BCM5400_GB_CONTROL); >- data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; >- phy_write(gp, MII_BCM5400_GB_CONTROL, data); >- >- mdelay(10); >- >- /* Reset and configure cascaded 10/100 PHY */ >- gem_reset_one_mii_phy(gp, 0x1f); >- >- data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f); >- data |= MII_BCM5201_MULTIPHY_SERIALMODE; >- __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); >- >- data = phy_read(gp, MII_BCM5400_AUXCONTROL); >- data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; >- phy_write(gp, MII_BCM5400_AUXCONTROL, data); >-} >- >-/* Must be invoked under gp->lock. */ >-static void gem_init_bcm5401_phy(struct gem *gp) >-{ >- u16 data; >- int rev; >- >- rev = phy_read(gp, MII_PHYSID2) & 0x000f; >- if (rev == 0 || rev == 3) { >- /* 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 >- * >- * Note: This should (and does) match tg3_init_5401phy_dsp >- * in the tg3.c driver. -DaveM >- */ >- phy_write(gp, 0x18, 0x0c20); >- phy_write(gp, 0x17, 0x0012); >- phy_write(gp, 0x15, 0x1804); >- phy_write(gp, 0x17, 0x0013); >- phy_write(gp, 0x15, 0x1204); >- phy_write(gp, 0x17, 0x8006); >- phy_write(gp, 0x15, 0x0132); >- phy_write(gp, 0x17, 0x8006); >- phy_write(gp, 0x15, 0x0232); >- phy_write(gp, 0x17, 0x201f); >- phy_write(gp, 0x15, 0x0a20); >- } >- >- /* Configure for gigabit full duplex */ >- data = phy_read(gp, MII_BCM5400_GB_CONTROL); >- data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; >- phy_write(gp, MII_BCM5400_GB_CONTROL, data); >- >- mdelay(1); >- >- /* Reset and configure cascaded 10/100 PHY */ >- gem_reset_one_mii_phy(gp, 0x1f); >- >- data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f); >- data |= MII_BCM5201_MULTIPHY_SERIALMODE; >- __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); >-} >- >-/* Must be invoked under gp->lock. */ >-static void gem_init_bcm5411_phy(struct gem *gp) >-{ >- u16 data; >- >- /* Here's some more Apple black magic to setup >- * some voltage stuffs. >- */ >- phy_write(gp, 0x1c, 0x8c23); >- phy_write(gp, 0x1c, 0x8ca3); >- phy_write(gp, 0x1c, 0x8c23); >- >- /* Here, Apple seems to want to reset it, do >- * it as well >- */ >- phy_write(gp, MII_BMCR, BMCR_RESET); >- >- /* Start autoneg */ >- phy_write(gp, MII_BMCR, >- (BMCR_ANENABLE | BMCR_FULLDPLX | >- BMCR_ANRESTART | BMCR_SPD2)); >- >- data = phy_read(gp, MII_BCM5400_GB_CONTROL); >- data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; >- phy_write(gp, MII_BCM5400_GB_CONTROL, data); >+ mb(); > } > > /* Must be invoked under gp->lock. */ > static void gem_init_phy(struct gem *gp) > { > u32 mifcfg; >- >- if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) >- phy_write(gp, MII_BCM5201_INTERRUPT, 0); >- >+ > /* Revert MIF CFG setting done on stop_phy */ > mifcfg = readl(gp->regs + MIF_CFG); > mifcfg &= ~MIF_CFG_BBMODE; >@@ -1655,19 +1499,37 @@ > > #ifdef CONFIG_ALL_PPC > if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { >- int i; >+ int i, j; > >+ /* Those delay sucks, the HW seem to love them though, I'll >+ * serisouly consider breaking some locks here to be able >+ * to schedule instead >+ */ > pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0); >- for (i = 0; i < 32; i++) { >- gp->mii_phy_addr = i; >- if (phy_read(gp, MII_BMCR) != 0xffff) >+ mdelay(10); >+ for (j = 0; j < 3; j++) { >+ /* Some PHYs used by apple have problem getting back to us, >+ * we _know_ it's actually at addr 0, that's a hack, but >+ * it helps to do that reset now. I suspect some motherboards >+ * don't wire the PHY reset line properly, thus the PHY doesn't >+ * come back with the above pmac_call_feature. >+ */ >+ gp->mii_phy_addr = 0; >+ phy_write(gp, MII_BMCR, BMCR_RESET); >+ /* We should probably break some locks here and schedule... */ >+ mdelay(10); >+ for (i = 0; i < 32; i++) { >+ gp->mii_phy_addr = i; >+ if (phy_read(gp, MII_BMCR) != 0xffff) >+ break; >+ } >+ if (i == 32) { >+ printk(KERN_WARNING "%s: GMAC PHY not responding !\n", >+ gp->dev->name); >+ gp->mii_phy_addr = 0; >+ } else > break; > } >- if (i == 32) { >- printk(KERN_WARNING "%s: GMAC PHY not responding !\n", >- gp->dev->name); >- return; >- } > } > #endif /* CONFIG_ALL_PPC */ > >@@ -1690,79 +1552,12 @@ > > if (gp->phy_type == phy_mii_mdio0 || > gp->phy_type == phy_mii_mdio1) { >- u32 phy_id; >- u16 val; >- >- /* Take PHY out of isloate mode and reset it. */ >- gem_reset_one_mii_phy(gp, gp->mii_phy_addr); >- >- phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2)) >- & 0xfffffff0; >- printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id); >- switch(phy_id) { >- case 0x406210: >- gp->phy_mod = phymod_bcm5201; >- gem_init_bcm5201_phy(gp); >- printk("BCM 5201\n"); >- break; >- >- case 0x4061e0: >- printk("BCM 5221\n"); >- gp->phy_mod = phymod_bcm5221; >- break; >- >- case 0x206040: >- printk("BCM 5400\n"); >- gp->phy_mod = phymod_bcm5400; >- gem_init_bcm5400_phy(gp); >- gp->gigabit_capable = 1; >- break; >- >- case 0x206050: >- printk("BCM 5401\n"); >- gp->phy_mod = phymod_bcm5401; >- gem_init_bcm5401_phy(gp); >- gp->gigabit_capable = 1; >- break; >- >- case 0x206070: >- printk("BCM 5411\n"); >- gp->phy_mod = phymod_bcm5411; >- gem_init_bcm5411_phy(gp); >- gp->gigabit_capable = 1; >- break; >- case 0x1410c60: >- printk("M1011 (Marvel ?)\n"); >- gp->phy_mod = phymod_m1011; >- gp->gigabit_capable = 1; >- break; >- >- case 0x18074c0: >- printk("Lucent\n"); >- gp->phy_mod = phymod_generic; >- break; >- >- case 0x437420: >- printk("Enable Semiconductor\n"); >- gp->phy_mod = phymod_generic; >- break; >- >- default: >- printk("Unknown (Using generic mode)\n"); >- gp->phy_mod = phymod_generic; >- break; >- }; >+ // XXX check for errors >+ mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr); > >- /* Init advertisement and enable autonegotiation. */ >- val = phy_read(gp, MII_BMCR); >- val &= ~BMCR_ANENABLE; >- phy_write(gp, MII_BMCR, val); >- udelay(10); >- >- phy_write(gp, MII_ADVERTISE, >- phy_read(gp, MII_ADVERTISE) | >- (ADVERTISE_10HALF | ADVERTISE_10FULL | >- ADVERTISE_100HALF | ADVERTISE_100FULL)); >+ /* Init PHY */ >+ if (gp->phy_mii.def && gp->phy_mii.def->ops->init) >+ gp->phy_mii.def->ops->init(&gp->phy_mii); > } else { > u32 val; > int limit; >@@ -1819,13 +1614,7 @@ > else > val |= PCS_SCTRL_LOOP; > writel(val, gp->regs + PCS_SCTRL); >- gp->gigabit_capable = 1; > } >- >- /* BMCR_SPD2 is a broadcom 54xx specific thing afaik */ >- if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 && >- gp->phy_mod != phymod_bcm5411) >- gp->link_cntl &= ~BMCR_SPD2; > } > > /* Must be invoked under gp->lock. */ >@@ -1914,9 +1703,7 @@ > { > unsigned char *e = &gp->dev->dev_addr[0]; > >- if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && >- gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) >- writel(0x1bf0, gp->regs + MAC_SNDPAUSE); >+ writel(0x1bf0, gp->regs + MAC_SNDPAUSE); > > writel(0x00, gp->regs + MAC_IPG0); > writel(0x08, gp->regs + MAC_IPG1); >@@ -1953,7 +1740,9 @@ > writel(0, gp->regs + MAC_AF0MSK); > > gp->mac_rx_cfg = gem_setup_multicast(gp); >- >+#ifdef STRIP_FCS >+ gp->mac_rx_cfg |= MAC_RXCFG_SFCS; >+#endif > writel(0, gp->regs + MAC_NCOLL); > writel(0, gp->regs + MAC_FASUCC); > writel(0, gp->regs + MAC_ECOLL); >@@ -2129,12 +1918,15 @@ > /* Default aneg parameters */ > gp->timer_ticks = 0; > gp->lstate = link_down; >+ netif_carrier_off(gp->dev); > > /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ > gem_begin_auto_negotiation(gp, NULL); > } else { >- if (gp->lstate == link_up) >+ if (gp->lstate == link_up) { >+ netif_carrier_on(gp->dev); > gem_set_link_modes(gp); >+ } > } > } > >@@ -2184,9 +1976,6 @@ > { > u32 mifcfg; > >- if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) >- phy_write(gp, MII_BCM5201_INTERRUPT, 0); >- > /* Make sure we aren't polling PHY status change. We > * don't currently use that feature though > */ >@@ -2194,9 +1983,6 @@ > mifcfg &= ~MIF_CFG_POLL; > writel(mifcfg, gp->regs + MIF_CFG); > >- /* Here's a strange hack used by both MacOS 9 and X */ >- phy_write(gp, MII_LPA, phy_read(gp, MII_LPA)); >- > if (gp->wake_on_lan) { > /* Setup wake-on-lan */ > } else >@@ -2210,21 +1996,12 @@ > gem_stop(gp); > writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); > writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); >- if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 || >- gp->phy_mod == phymod_bcm5411) { >-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ >- phy_write(gp, MII_BMCR, BMCR_PDOWN); >-#endif >- } else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) { >-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ >- u16 val = phy_read(gp, MII_BCM5201_AUXMODE2) >- phy_write(gp, MII_BCM5201_AUXMODE2, >- val & ~MII_BCM5201_AUXMODE2_LOWPOWER); >-#endif >- phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); >- } else if (gp->phy_mod == phymod_m1011) >- phy_write(gp, MII_BMCR, BMCR_PDOWN); >+ } > >+ if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend) >+ gp->phy_mii.def->ops->suspend(&gp->phy_mii, 0 /* wake on lan options */); >+ >+ if (!gp->wake_on_lan) { > /* According to Apple, we must set the MDIO pins to this begnign > * state or we may 1) eat more current, 2) damage some PHYs > */ >@@ -2330,15 +2107,11 @@ > gp->hw_running = 1; > } > >- spin_lock_irq(&gp->lock); >- > /* We can now request the interrupt as we know it's masked > * on the controller > */ > if (request_irq(gp->pdev->irq, gem_interrupt, > SA_SHIRQ, dev->name, (void *)dev)) { >- spin_unlock_irq(&gp->lock); >- > printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); > > #ifdef CONFIG_ALL_PPC >@@ -2349,10 +2122,13 @@ > gp->pm_timer.expires = jiffies + 10*HZ; > add_timer(&gp->pm_timer); > up(&gp->pm_sem); >+ spin_unlock_irq(&gp->lock); > > return -EAGAIN; > } > >+ spin_lock_irq(&gp->lock); >+ > /* Allocate & setup ring buffers */ > gem_init_rings(gp); > >@@ -2526,7 +2302,11 @@ > netif_stop_queue(dev); > > rxcfg = readl(gp->regs + MAC_RXCFG); >- gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp); >+ rxcfg_new = gem_setup_multicast(gp); >+#ifdef STRIP_FCS >+ rxcfg_new |= MAC_RXCFG_SFCS; >+#endif >+ gp->mac_rx_cfg = rxcfg_new; > > writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); > while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) { >@@ -2551,8 +2331,6 @@ > static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user) > { > struct gem *gp = dev->priv; >- u16 bmcr; >- int full_duplex, speed, pause; > struct ethtool_cmd ecmd; > > if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) >@@ -2560,7 +2338,7 @@ > > switch(ecmd.cmd) { > case ETHTOOL_GDRVINFO: { >- struct ethtool_drvinfo info = { cmd: ETHTOOL_GDRVINFO }; >+ struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO }; > > strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN); > strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN); >@@ -2575,41 +2353,36 @@ > } > > case ETHTOOL_GSET: >- ecmd.supported = >+ if (gp->phy_type == phy_mii_mdio0 || >+ gp->phy_type == phy_mii_mdio1) { >+ if (gp->phy_mii.def) >+ ecmd.supported = gp->phy_mii.def->features; >+ else >+ ecmd.supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full; >+ >+ /* XXX hardcoded stuff for now */ >+ ecmd.port = PORT_MII; >+ ecmd.transceiver = XCVR_EXTERNAL; >+ ecmd.phy_address = 0; /* XXX fixed PHYAD */ >+ >+ /* Return current PHY settings */ >+ spin_lock_irq(&gp->lock); >+ ecmd.autoneg = gp->want_autoneg; >+ ecmd.speed = gp->phy_mii.speed; >+ ecmd.duplex = gp->phy_mii.duplex; >+ ecmd.advertising = gp->phy_mii.advertising; >+ /* If we started with a forced mode, we don't have a default >+ * advertise set, we need to return something sensible so >+ * userland can re-enable autoneg properly */ >+ if (ecmd.advertising == 0) >+ ecmd.advertising = ecmd.supported; >+ spin_unlock_irq(&gp->lock); >+ } else { // XXX PCS ? >+ ecmd.supported = > (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | > SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | >- SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); >- >- if (gp->gigabit_capable) >- ecmd.supported |= >- (SUPPORTED_1000baseT_Half | >- SUPPORTED_1000baseT_Full); >- >- /* XXX hardcoded stuff for now */ >- ecmd.port = PORT_MII; >- ecmd.transceiver = XCVR_EXTERNAL; >- ecmd.phy_address = 0; /* XXX fixed PHYAD */ >- >- /* Record PHY settings if HW is on. */ >- spin_lock_irq(&gp->lock); >- if (gp->hw_running) { >- bmcr = phy_read(gp, MII_BMCR); >- gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); >- } else >- bmcr = 0; >- spin_unlock_irq(&gp->lock); >- if (bmcr & BMCR_ANENABLE) { >- ecmd.autoneg = AUTONEG_ENABLE; >- ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100); >- ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; >- } else { >- ecmd.autoneg = AUTONEG_DISABLE; >- ecmd.speed = >- (bmcr & BMCR_SPEED100) ? >- SPEED_100 : SPEED_10; >- ecmd.duplex = >- (bmcr & BMCR_FULLDPLX) ? >- DUPLEX_FULL : DUPLEX_HALF; >+ SUPPORTED_Autoneg); >+ ecmd.advertising = ecmd.supported; > } > if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) > return -EFAULT; >@@ -2621,13 +2394,18 @@ > ecmd.autoneg != AUTONEG_DISABLE) > return -EINVAL; > >+ if (ecmd.autoneg == AUTONEG_ENABLE && >+ ecmd.advertising == 0) >+ return -EINVAL; >+ > if (ecmd.autoneg == AUTONEG_DISABLE && >- ((ecmd.speed != SPEED_100 && >+ ((ecmd.speed != SPEED_1000 && >+ ecmd.speed != SPEED_100 && > ecmd.speed != SPEED_10) || > (ecmd.duplex != DUPLEX_HALF && > ecmd.duplex != DUPLEX_FULL))) > return -EINVAL; >- >+ > /* Apply settings and restart link process. */ > spin_lock_irq(&gp->lock); > gem_begin_auto_negotiation(gp, &ecmd); >@@ -2636,7 +2414,7 @@ > return 0; > > case ETHTOOL_NWAY_RST: >- if ((gp->link_cntl & BMCR_ANENABLE) == 0) >+ if (!gp->want_autoneg) > return -EINVAL; > > /* Restart link process. */ >@@ -2652,7 +2430,7 @@ > > /* get link status */ > case ETHTOOL_GLINK: { >- struct ethtool_value edata = { cmd: ETHTOOL_GLINK }; >+ struct ethtool_value edata = { .cmd = ETHTOOL_GLINK }; > > edata.data = (gp->lstate == link_up); > if (copy_to_user(ep_user, &edata, sizeof(edata))) >@@ -2662,7 +2440,7 @@ > > /* get message-level */ > case ETHTOOL_GMSGLVL: { >- struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL }; >+ struct ethtool_value edata = { .cmd = ETHTOOL_GMSGLVL }; > > edata.data = gp->msg_enable; > if (copy_to_user(ep_user, &edata, sizeof(edata))) >@@ -2740,15 +2518,21 @@ > /* Fallthrough... */ > > case SIOCGMIIREG: /* Read MII PHY register. */ >- data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f); >- rc = 0; >+ if (!gp->hw_running) >+ rc = -EIO; >+ else { >+ data->val_out = __phy_read(gp, data->phy_id & 0x1f, data->reg_num & 0x1f); >+ rc = 0; >+ } > break; > > case SIOCSMIIREG: /* Write MII PHY register. */ >- if (!capable(CAP_NET_ADMIN)) { >+ if (!capable(CAP_NET_ADMIN)) > rc = -EPERM; >- } else { >- __phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f); >+ else if (!gp->hw_running) >+ rc = -EIO; >+ else { >+ __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); > rc = 0; > } > break; >@@ -2894,7 +2678,7 @@ > */ > if (pdev->vendor == PCI_VENDOR_ID_SUN && > pdev->device == PCI_DEVICE_ID_SUN_GEM && >- !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { >+ !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { > pci_using_dac = 1; > } else { > err = pci_set_dma_mask(pdev, (u64) 0xffffffff); >@@ -2934,7 +2718,7 @@ > dev->base_addr = (long) pdev; > gp->dev = dev; > >- gp->msg_enable = (gem_debug < 0 ? DEFAULT_MSG : gem_debug); >+ gp->msg_enable = DEFAULT_MSG; > > spin_lock_init(&gp->lock); > init_MUTEX(&gp->pm_sem); >@@ -2950,13 +2734,9 @@ > INIT_TQUEUE(&gp->pm_task, gem_pm_task, gp); > INIT_TQUEUE(&gp->reset_task, gem_reset_task, gp); > >- /* Default link parameters */ >- if (link_mode >= 0 && link_mode <= 6) >- gp->link_cntl = link_modes[link_mode]; >- else >- gp->link_cntl = BMCR_ANENABLE; > gp->lstate = link_down; > gp->timer_ticks = 0; >+ netif_carrier_off(dev); > > gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); > if (gp->regs == 0UL) { >@@ -2977,16 +2757,18 @@ > gem_stop(gp); > spin_unlock_irq(&gp->lock); > >+ /* Fill up the mii_phy structure (even if we won't use it) */ >+ gp->phy_mii.dev = dev; >+ gp->phy_mii.mdio_read = _phy_read; >+ gp->phy_mii.mdio_write = _phy_write; >+ >+ /* By default, we start with autoneg */ >+ gp->want_autoneg = 1; >+ > if (gem_check_invariants(gp)) > goto err_out_iounmap; > >- spin_lock_irq(&gp->lock); >- gp->hw_running = 1; >- gem_init_phy(gp); >- gem_begin_auto_negotiation(gp, NULL); >- spin_unlock_irq(&gp->lock); >- >- /* It is guarenteed that the returned buffer will be at least >+ /* It is guaranteed that the returned buffer will be at least > * PAGE_SIZE aligned. > */ > gp->init_block = (struct gem_init_block *) >@@ -3012,12 +2794,23 @@ > > printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", > dev->name); >- > for (i = 0; i < 6; i++) > printk("%2.2x%c", dev->dev_addr[i], > i == 5 ? ' ' : ':'); > printk("\n"); > >+ /* Detect & init PHY, start autoneg */ >+ spin_lock_irq(&gp->lock); >+ gp->hw_running = 1; >+ gem_init_phy(gp); >+ gem_begin_auto_negotiation(gp, NULL); >+ spin_unlock_irq(&gp->lock); >+ >+ if (gp->phy_type == phy_mii_mdio0 || >+ gp->phy_type == phy_mii_mdio1) >+ printk(KERN_INFO "%s: Found %s PHY\n", dev->name, >+ gp->phy_mii.def ? gp->phy_mii.def->name : "no"); >+ > pci_set_drvdata(pdev, dev); > > dev->open = gem_open; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/sungem.h linux-2.4.22-ppc-dev/drivers/net/sungem.h >--- linux-2.4.22-ppc-dev.orig/drivers/net/sungem.h 2002-08-03 02:39:44.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/sungem.h 2003-08-25 23:37:33.000000000 +0200 >@@ -805,14 +805,14 @@ > u64 buffer; > }; > >-#define TXDCTRL_BUFSZ 0x0000000000007fff /* Buffer Size */ >-#define TXDCTRL_CSTART 0x00000000001f8000 /* CSUM Start Offset */ >-#define TXDCTRL_COFF 0x000000001fe00000 /* CSUM Stuff Offset */ >-#define TXDCTRL_CENAB 0x0000000020000000 /* CSUM Enable */ >-#define TXDCTRL_EOF 0x0000000040000000 /* End of Frame */ >-#define TXDCTRL_SOF 0x0000000080000000 /* Start of Frame */ >-#define TXDCTRL_INTME 0x0000000100000000 /* "Interrupt Me" */ >-#define TXDCTRL_NOCRC 0x0000000200000000 /* No CRC Present */ >+#define TXDCTRL_BUFSZ 0x0000000000007fffULL /* Buffer Size */ >+#define TXDCTRL_CSTART 0x00000000001f8000ULL /* CSUM Start Offset */ >+#define TXDCTRL_COFF 0x000000001fe00000ULL /* CSUM Stuff Offset */ >+#define TXDCTRL_CENAB 0x0000000020000000ULL /* CSUM Enable */ >+#define TXDCTRL_EOF 0x0000000040000000ULL /* End of Frame */ >+#define TXDCTRL_SOF 0x0000000080000000ULL /* Start of Frame */ >+#define TXDCTRL_INTME 0x0000000100000000ULL /* "Interrupt Me" */ >+#define TXDCTRL_NOCRC 0x0000000200000000ULL /* No CRC Present */ > > /* GEM requires that RX descriptors are provided four at a time, > * aligned. Also, the RX ring may not wrap around. This means that >@@ -840,13 +840,13 @@ > u64 buffer; > }; > >-#define RXDCTRL_TCPCSUM 0x000000000000ffff /* TCP Pseudo-CSUM */ >-#define RXDCTRL_BUFSZ 0x000000007fff0000 /* Buffer Size */ >-#define RXDCTRL_OWN 0x0000000080000000 /* GEM owns this entry */ >-#define RXDCTRL_HASHVAL 0x0ffff00000000000 /* Hash Value */ >-#define RXDCTRL_HPASS 0x1000000000000000 /* Passed Hash Filter */ >-#define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ >-#define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ >+#define RXDCTRL_TCPCSUM 0x000000000000ffffULL /* TCP Pseudo-CSUM */ >+#define RXDCTRL_BUFSZ 0x000000007fff0000ULL /* Buffer Size */ >+#define RXDCTRL_OWN 0x0000000080000000ULL /* GEM owns this entry */ >+#define RXDCTRL_HASHVAL 0x0ffff00000000000ULL /* Hash Value */ >+#define RXDCTRL_HPASS 0x1000000000000000ULL /* Passed Hash Filter */ >+#define RXDCTRL_ALTMAC 0x2000000000000000ULL /* Matched ALT MAC */ >+#define RXDCTRL_BAD 0x4000000000000000ULL /* Frame has bad CRC */ > > #define RXDCTRL_FRESH(gp) \ > ((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ >@@ -936,16 +936,6 @@ > phy_serdes, > }; > >-enum gem_phy_model { >- phymod_generic, >- phymod_bcm5201, >- phymod_bcm5221, >- phymod_bcm5400, >- phymod_bcm5401, >- phymod_bcm5411, >- phymod_m1011, >-}; >- > enum link_state { > link_down = 0, /* No link, will retry */ > link_aneg, /* Autoneg in progress */ >@@ -980,21 +970,20 @@ > struct net_device_stats net_stats; > > enum gem_phy_type phy_type; >- enum gem_phy_model phy_mod; >+ struct mii_phy phy_mii; >+ > int tx_fifo_sz; > int rx_fifo_sz; > int rx_pause_off; > int rx_pause_on; > int mii_phy_addr; >- int gigabit_capable; > > u32 mac_rx_cfg; > u32 swrst_base; > > /* Autoneg & PHY control */ >- int link_cntl; >- int link_advertise; >- int link_fcntl; >+ int want_autoneg; >+ int last_forced_speed; > enum link_state lstate; > struct timer_list link_timer; > int timer_ticks; >@@ -1014,6 +1003,9 @@ > #endif > }; > >+#define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) \ >+ && gp->phy_mii.def && gp->phy_mii.def->ops) >+ > #define ALIGNED_RX_SKB_ADDR(addr) \ > ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) > static __inline__ struct sk_buff *gem_alloc_skb(int size, int gfp_flags) >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/sungem_phy.c linux-2.4.22-ppc-dev/drivers/net/sungem_phy.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/sungem_phy.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/net/sungem_phy.c 2003-08-25 23:38:02.000000000 +0200 >@@ -0,0 +1,838 @@ >+/* >+ * PHY drivers for the sungem ethernet driver. >+ * >+ * This file could be shared with other drivers. >+ * >+ * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org) >+ * >+ * TODO: >+ * - Implement WOL >+ * - Add support for PHYs that provide an IRQ line >+ * - Eventually moved the entire polling state machine in >+ * there (out of the eth driver), so that it can easily be >+ * skipped on PHYs that implement it in hardware. >+ * - On LXT971 & BCM5201, Apple uses some chip specific regs >+ * to read the link status. Figure out why and if it makes >+ * sense to do the same (magic aneg ?) >+ * - Apple has some additional power management code for some >+ * Broadcom PHYs that they "hide" from the OpenSource version >+ * of darwin, still need to reverse engineer that >+ */ >+ >+#include <linux/config.h> >+ >+#include <linux/module.h> >+ >+#include <linux/kernel.h> >+#include <linux/sched.h> >+#include <linux/types.h> >+#include <linux/netdevice.h> >+#include <linux/etherdevice.h> >+#include <linux/mii.h> >+#include <linux/ethtool.h> >+#include <linux/delay.h> >+ >+#include "sungem_phy.h" >+ >+/* Link modes of the BCM5400 PHY */ >+static int phy_BCM5400_link_table[8][3] = { >+ { 0, 0, 0 }, /* No link */ >+ { 0, 0, 0 }, /* 10BT Half Duplex */ >+ { 1, 0, 0 }, /* 10BT Full Duplex */ >+ { 0, 1, 0 }, /* 100BT Half Duplex */ >+ { 0, 1, 0 }, /* 100BT Half Duplex */ >+ { 1, 1, 0 }, /* 100BT Full Duplex*/ >+ { 1, 0, 1 }, /* 1000BT */ >+ { 1, 0, 1 }, /* 1000BT */ >+}; >+ >+static inline int __phy_read(struct mii_phy* phy, int id, int reg) >+{ >+ return phy->mdio_read(phy->dev, id, reg); >+} >+ >+static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val) >+{ >+ phy->mdio_write(phy->dev, id, reg, val); >+} >+ >+static inline int phy_read(struct mii_phy* phy, int reg) >+{ >+ return phy->mdio_read(phy->dev, phy->mii_id, reg); >+} >+ >+static inline void phy_write(struct mii_phy* phy, int reg, int val) >+{ >+ phy->mdio_write(phy->dev, phy->mii_id, reg, val); >+} >+ >+static int reset_one_mii_phy(struct mii_phy* phy, int phy_id) >+{ >+ u16 val; >+ int limit = 10000; >+ >+ val = __phy_read(phy, phy_id, MII_BMCR); >+ val &= ~BMCR_ISOLATE; >+ val |= BMCR_RESET; >+ __phy_write(phy, phy_id, MII_BMCR, val); >+ >+ udelay(100); >+ >+ while (limit--) { >+ val = __phy_read(phy, phy_id, MII_BMCR); >+ if ((val & BMCR_RESET) == 0) >+ break; >+ udelay(10); >+ } >+ if ((val & BMCR_ISOLATE) && limit > 0) >+ __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE); >+ >+ return (limit <= 0); >+} >+ >+static int bcm5201_init(struct mii_phy* phy) >+{ >+ u16 data; >+ >+ data = phy_read(phy, MII_BCM5201_MULTIPHY); >+ data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE; >+ phy_write(phy, MII_BCM5201_MULTIPHY, data); >+ >+ return 0; >+} >+ >+static int bcm5201_suspend(struct mii_phy* phy, int wol_options) >+{ >+ if (!wol_options) >+ phy_write(phy, MII_BCM5201_INTERRUPT, 0); >+ >+ /* Here's a strange hack used by both MacOS 9 and X */ >+ phy_write(phy, MII_LPA, phy_read(phy, MII_LPA)); >+ >+ if (!wol_options) { >+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ >+ u16 val = phy_read(phy, MII_BCM5201_AUXMODE2) >+ phy_write(phy, MII_BCM5201_AUXMODE2, >+ val & ~MII_BCM5201_AUXMODE2_LOWPOWER); >+#endif >+ phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); >+ } >+ >+ return 0; >+} >+ >+static int bcm5221_init(struct mii_phy* phy) >+{ >+ u16 data; >+ >+ data = phy_read(phy, MII_BCM5221_TEST); >+ phy_write(phy, MII_BCM5221_TEST, >+ data | MII_BCM5221_TEST_ENABLE_SHADOWS); >+ >+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2); >+ phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2, >+ data | MII_BCM5221_SHDOW_AUX_STAT2_APD); >+ >+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4); >+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4, >+ data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR); >+ >+ data = phy_read(phy, MII_BCM5221_TEST); >+ phy_write(phy, MII_BCM5221_TEST, >+ data & ~MII_BCM5221_TEST_ENABLE_SHADOWS); >+ >+ return 0; >+} >+ >+static int bcm5400_init(struct mii_phy* phy) >+{ >+ u16 data; >+ >+ /* Configure for gigabit full duplex */ >+ data = phy_read(phy, MII_BCM5400_AUXCONTROL); >+ data |= MII_BCM5400_AUXCONTROL_PWR10BASET; >+ phy_write(phy, MII_BCM5400_AUXCONTROL, data); >+ >+ data = phy_read(phy, MII_BCM5400_GB_CONTROL); >+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; >+ phy_write(phy, MII_BCM5400_GB_CONTROL, data); >+ >+ mdelay(10); >+ >+ /* Reset and configure cascaded 10/100 PHY */ >+ (void)reset_one_mii_phy(phy, 0x1f); >+ >+ data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY); >+ data |= MII_BCM5201_MULTIPHY_SERIALMODE; >+ __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data); >+ >+ data = phy_read(phy, MII_BCM5400_AUXCONTROL); >+ data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; >+ phy_write(phy, MII_BCM5400_AUXCONTROL, data); >+ >+ return 0; >+} >+ >+static int bcm5400_suspend(struct mii_phy* phy, int wol_options) >+{ >+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ >+ phy_write(phy, MII_BMCR, BMCR_PDOWN); >+#endif >+ return 0; >+} >+ >+static int bcm5401_init(struct mii_phy* phy) >+{ >+ u16 data; >+ int rev; >+ >+ rev = phy_read(phy, MII_PHYSID2) & 0x000f; >+ if (rev == 0 || rev == 3) { >+ /* 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 >+ * >+ * Note: This should (and does) match tg3_init_5401phy_dsp >+ * in the tg3.c driver. -DaveM >+ */ >+ phy_write(phy, 0x18, 0x0c20); >+ phy_write(phy, 0x17, 0x0012); >+ phy_write(phy, 0x15, 0x1804); >+ phy_write(phy, 0x17, 0x0013); >+ phy_write(phy, 0x15, 0x1204); >+ phy_write(phy, 0x17, 0x8006); >+ phy_write(phy, 0x15, 0x0132); >+ phy_write(phy, 0x17, 0x8006); >+ phy_write(phy, 0x15, 0x0232); >+ phy_write(phy, 0x17, 0x201f); >+ phy_write(phy, 0x15, 0x0a20); >+ } >+ >+ /* Configure for gigabit full duplex */ >+ data = phy_read(phy, MII_BCM5400_GB_CONTROL); >+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; >+ phy_write(phy, MII_BCM5400_GB_CONTROL, data); >+ >+ mdelay(10); >+ >+ /* Reset and configure cascaded 10/100 PHY */ >+ (void)reset_one_mii_phy(phy, 0x1f); >+ >+ data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY); >+ data |= MII_BCM5201_MULTIPHY_SERIALMODE; >+ __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data); >+ >+ return 0; >+} >+ >+static int bcm5401_suspend(struct mii_phy* phy, int wol_options) >+{ >+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ >+ phy_write(phy, MII_BMCR, BMCR_PDOWN); >+#endif >+ return 0; >+} >+ >+static int bcm5411_init(struct mii_phy* phy) >+{ >+ u16 data; >+ >+ /* Here's some more Apple black magic to setup >+ * some voltage stuffs. >+ */ >+ phy_write(phy, 0x1c, 0x8c23); >+ phy_write(phy, 0x1c, 0x8ca3); >+ phy_write(phy, 0x1c, 0x8c23); >+ >+ /* Here, Apple seems to want to reset it, do >+ * it as well >+ */ >+ phy_write(phy, MII_BMCR, BMCR_RESET); >+ phy_write(phy, MII_BMCR, 0x1340); >+ >+ data = phy_read(phy, MII_BCM5400_GB_CONTROL); >+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; >+ phy_write(phy, MII_BCM5400_GB_CONTROL, data); >+ >+ mdelay(10); >+ >+ /* Reset and configure cascaded 10/100 PHY */ >+ (void)reset_one_mii_phy(phy, 0x1f); >+ >+ return 0; >+} >+ >+static int bcm5411_suspend(struct mii_phy* phy, int wol_options) >+{ >+ phy_write(phy, MII_BMCR, BMCR_PDOWN); >+ >+ return 0; >+} >+ >+static int bcm5421_init(struct mii_phy* phy) >+{ >+ u16 data; >+ int rev; >+ >+ rev = phy_read(phy, MII_PHYSID2) & 0x000f; >+ if (rev == 0) { >+ /* This is borrowed from MacOS >+ */ >+ phy_write(phy, 0x18, 0x1007); >+ data = phy_read(phy, 0x18); >+ phy_write(phy, 0x18, data | 0x0400); >+ phy_write(phy, 0x18, 0x0007); >+ data = phy_read(phy, 0x18); >+ phy_write(phy, 0x18, data | 0x0800); >+ phy_write(phy, 0x17, 0x000a); >+ data = phy_read(phy, 0x15); >+ phy_write(phy, 0x15, data | 0x0200); >+ } >+#if 0 >+ /* This has to be verified before I enable it */ >+ /* Enable automatic low-power */ >+ phy_write(phy, 0x1c, 0x9002); >+ phy_write(phy, 0x1c, 0xa821); >+ phy_write(phy, 0x1c, 0x941d); >+#endif >+ return 0; >+} >+ >+static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) >+{ >+ u16 ctl, adv; >+ >+ phy->autoneg = 1; >+ phy->speed = SPEED_10; >+ phy->duplex = DUPLEX_HALF; >+ phy->pause = 0; >+ phy->advertising = advertise; >+ >+ /* Setup standard advertise */ >+ adv = phy_read(phy, MII_ADVERTISE); >+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); >+ if (advertise & ADVERTISED_10baseT_Half) >+ adv |= ADVERTISE_10HALF; >+ if (advertise & ADVERTISED_10baseT_Full) >+ adv |= ADVERTISE_10FULL; >+ if (advertise & ADVERTISED_100baseT_Half) >+ adv |= ADVERTISE_100HALF; >+ if (advertise & ADVERTISED_100baseT_Full) >+ adv |= ADVERTISE_100FULL; >+ phy_write(phy, MII_ADVERTISE, adv); >+ >+ /* Setup 1000BT advertise */ >+ adv = phy_read(phy, MII_1000BASETCONTROL); >+ adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP); >+ if (advertise & SUPPORTED_1000baseT_Half) >+ adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; >+ if (advertise & SUPPORTED_1000baseT_Full) >+ adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; >+ phy_write(phy, MII_1000BASETCONTROL, adv); >+ >+ /* Start/Restart aneg */ >+ ctl = phy_read(phy, MII_BMCR); >+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); >+ phy_write(phy, MII_BMCR, ctl); >+ >+ return 0; >+} >+ >+static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd) >+{ >+ u16 ctl; >+ >+ phy->autoneg = 0; >+ phy->speed = speed; >+ phy->duplex = fd; >+ phy->pause = 0; >+ >+ ctl = phy_read(phy, MII_BMCR); >+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); >+ >+ /* First reset the PHY */ >+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET); >+ >+ /* Select speed & duplex */ >+ switch(speed) { >+ case SPEED_10: >+ break; >+ case SPEED_100: >+ ctl |= BMCR_SPEED100; >+ break; >+ case SPEED_1000: >+ ctl |= BMCR_SPD2; >+ } >+ if (fd == DUPLEX_FULL) >+ ctl |= BMCR_FULLDPLX; >+ >+ // XXX Should we set the sungem to GII now on 1000BT ? >+ >+ phy_write(phy, MII_BMCR, ctl); >+ >+ return 0; >+} >+ >+static int bcm54xx_read_link(struct mii_phy *phy) >+{ >+ int link_mode; >+ u16 val; >+ >+ if (phy->autoneg) { >+ val = phy_read(phy, MII_BCM5400_AUXSTATUS); >+ link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> >+ MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); >+ phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF; >+ phy->speed = phy_BCM5400_link_table[link_mode][2] ? >+ SPEED_1000 : >+ (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10); >+ val = phy_read(phy, MII_LPA); >+ phy->pause = ((val & LPA_PAUSE) != 0); >+ } >+ /* On non-aneg, we assume what we put in BMCR is the speed, >+ * though magic-aneg shouldn't prevent this case from occurring >+ */ >+ >+ return 0; >+} >+ >+static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) >+{ >+ u16 ctl, adv; >+ >+ phy->autoneg = 1; >+ phy->speed = SPEED_10; >+ phy->duplex = DUPLEX_HALF; >+ phy->pause = 0; >+ phy->advertising = advertise; >+ >+ /* Setup standard advertise */ >+ adv = phy_read(phy, MII_ADVERTISE); >+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); >+ if (advertise & ADVERTISED_10baseT_Half) >+ adv |= ADVERTISE_10HALF; >+ if (advertise & ADVERTISED_10baseT_Full) >+ adv |= ADVERTISE_10FULL; >+ if (advertise & ADVERTISED_100baseT_Half) >+ adv |= ADVERTISE_100HALF; >+ if (advertise & ADVERTISED_100baseT_Full) >+ adv |= ADVERTISE_100FULL; >+ phy_write(phy, MII_ADVERTISE, adv); >+ >+ /* Setup 1000BT advertise & enable crossover detect >+ * XXX How do we advertise 1000BT ? Darwin source is >+ * confusing here, they read from specific control and >+ * write to control... Someone has specs for those >+ * beasts ? >+ */ >+ adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); >+ adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX; >+ adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | >+ MII_1000BASETCONTROL_HALFDUPLEXCAP); >+ if (advertise & SUPPORTED_1000baseT_Half) >+ adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; >+ if (advertise & SUPPORTED_1000baseT_Full) >+ adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; >+ phy_write(phy, MII_1000BASETCONTROL, adv); >+ >+ /* Start/Restart aneg */ >+ ctl = phy_read(phy, MII_BMCR); >+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); >+ phy_write(phy, MII_BMCR, ctl); >+ >+ return 0; >+} >+ >+static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd) >+{ >+ u16 ctl, ctl2; >+ >+ phy->autoneg = 0; >+ phy->speed = speed; >+ phy->duplex = fd; >+ phy->pause = 0; >+ >+ ctl = phy_read(phy, MII_BMCR); >+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE); >+ ctl |= BMCR_RESET; >+ >+ /* Select speed & duplex */ >+ switch(speed) { >+ case SPEED_10: >+ break; >+ case SPEED_100: >+ ctl |= BMCR_SPEED100; >+ break; >+ /* I'm not sure about the one below, again, Darwin source is >+ * quite confusing and I lack chip specs >+ */ >+ case SPEED_1000: >+ ctl |= BMCR_SPD2; >+ } >+ if (fd == DUPLEX_FULL) >+ ctl |= BMCR_FULLDPLX; >+ >+ /* Disable crossover. Again, the way Apple does it is strange, >+ * though I don't assume they are wrong ;) >+ */ >+ ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL); >+ ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX | >+ MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX | >+ MII_1000BASETCONTROL_FULLDUPLEXCAP | >+ MII_1000BASETCONTROL_HALFDUPLEXCAP); >+ if (speed == SPEED_1000) >+ ctl2 |= (fd == DUPLEX_FULL) ? >+ MII_1000BASETCONTROL_FULLDUPLEXCAP : >+ MII_1000BASETCONTROL_HALFDUPLEXCAP; >+ phy_write(phy, MII_1000BASETCONTROL, ctl2); >+ >+ // XXX Should we set the sungem to GII now on 1000BT ? >+ >+ phy_write(phy, MII_BMCR, ctl); >+ >+ return 0; >+} >+ >+static int marvell_read_link(struct mii_phy *phy) >+{ >+ u16 status; >+ >+ if (phy->autoneg) { >+ status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS); >+ if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) >+ return -EAGAIN; >+ if (status & MII_M1011_PHY_SPEC_STATUS_1000) >+ phy->speed = SPEED_1000; >+ else if (status & MII_M1011_PHY_SPEC_STATUS_100) >+ phy->speed = SPEED_100; >+ else >+ phy->speed = SPEED_10; >+ if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) >+ phy->duplex = DUPLEX_FULL; >+ else >+ phy->duplex = DUPLEX_HALF; >+ phy->pause = 0; /* XXX Check against spec ! */ >+ } >+ /* On non-aneg, we assume what we put in BMCR is the speed, >+ * though magic-aneg shouldn't prevent this case from occurring >+ */ >+ >+ return 0; >+} >+ >+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) >+{ >+ u16 ctl, adv; >+ >+ phy->autoneg = 1; >+ phy->speed = SPEED_10; >+ phy->duplex = DUPLEX_HALF; >+ phy->pause = 0; >+ phy->advertising = advertise; >+ >+ /* Setup standard advertise */ >+ adv = phy_read(phy, MII_ADVERTISE); >+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); >+ if (advertise & ADVERTISED_10baseT_Half) >+ adv |= ADVERTISE_10HALF; >+ if (advertise & ADVERTISED_10baseT_Full) >+ adv |= ADVERTISE_10FULL; >+ if (advertise & ADVERTISED_100baseT_Half) >+ adv |= ADVERTISE_100HALF; >+ if (advertise & ADVERTISED_100baseT_Full) >+ adv |= ADVERTISE_100FULL; >+ phy_write(phy, MII_ADVERTISE, adv); >+ >+ /* Start/Restart aneg */ >+ ctl = phy_read(phy, MII_BMCR); >+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); >+ phy_write(phy, MII_BMCR, ctl); >+ >+ return 0; >+} >+ >+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) >+{ >+ u16 ctl; >+ >+ phy->autoneg = 0; >+ phy->speed = speed; >+ phy->duplex = fd; >+ phy->pause = 0; >+ >+ ctl = phy_read(phy, MII_BMCR); >+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); >+ >+ /* First reset the PHY */ >+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET); >+ >+ /* Select speed & duplex */ >+ switch(speed) { >+ case SPEED_10: >+ break; >+ case SPEED_100: >+ ctl |= BMCR_SPEED100; >+ break; >+ case SPEED_1000: >+ default: >+ return -EINVAL; >+ } >+ if (fd == DUPLEX_FULL) >+ ctl |= BMCR_FULLDPLX; >+ phy_write(phy, MII_BMCR, ctl); >+ >+ return 0; >+} >+ >+static int genmii_poll_link(struct mii_phy *phy) >+{ >+ u16 status; >+ >+ (void)phy_read(phy, MII_BMSR); >+ status = phy_read(phy, MII_BMSR); >+ if ((status & BMSR_LSTATUS) == 0) >+ return 0; >+ if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) >+ return 0; >+ return 1; >+} >+ >+static int genmii_read_link(struct mii_phy *phy) >+{ >+ u16 lpa; >+ >+ if (phy->autoneg) { >+ lpa = phy_read(phy, MII_LPA); >+ >+ if (lpa & (LPA_10FULL | LPA_100FULL)) >+ phy->duplex = DUPLEX_FULL; >+ else >+ phy->duplex = DUPLEX_HALF; >+ if (lpa & (LPA_100FULL | LPA_100HALF)) >+ phy->speed = SPEED_100; >+ else >+ phy->speed = SPEED_10; >+ phy->pause = 0; >+ } >+ /* On non-aneg, we assume what we put in BMCR is the speed, >+ * though magic-aneg shouldn't prevent this case from occurring >+ */ >+ >+ return 0; >+} >+ >+ >+#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ >+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ >+ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII) >+#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ >+ SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) >+ >+/* Broadcom BCM 5201 */ >+static struct mii_phy_ops bcm5201_phy_ops = { >+ init: bcm5201_init, >+ suspend: bcm5201_suspend, >+ setup_aneg: genmii_setup_aneg, >+ setup_forced: genmii_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: genmii_read_link, >+}; >+ >+static struct mii_phy_def bcm5201_phy_def = { >+ phy_id: 0x00406210, >+ phy_id_mask: 0xfffffff0, >+ name: "BCM5201", >+ features: MII_BASIC_FEATURES, >+ magic_aneg: 0, >+ ops: &bcm5201_phy_ops >+}; >+ >+/* Broadcom BCM 5221 */ >+static struct mii_phy_ops bcm5221_phy_ops = { >+ suspend: bcm5201_suspend, >+ init: bcm5221_init, >+ setup_aneg: genmii_setup_aneg, >+ setup_forced: genmii_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: genmii_read_link, >+}; >+ >+static struct mii_phy_def bcm5221_phy_def = { >+ phy_id: 0x004061e0, >+ phy_id_mask: 0xfffffff0, >+ name: "BCM5221", >+ features: MII_BASIC_FEATURES, >+ magic_aneg: 0, >+ ops: &bcm5221_phy_ops >+}; >+ >+/* Broadcom BCM 5400 */ >+static struct mii_phy_ops bcm5400_phy_ops = { >+ init: bcm5400_init, >+ suspend: bcm5400_suspend, >+ setup_aneg: bcm54xx_setup_aneg, >+ setup_forced: bcm54xx_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: bcm54xx_read_link, >+}; >+ >+static struct mii_phy_def bcm5400_phy_def = { >+ phy_id: 0x00206040, >+ phy_id_mask: 0xfffffff0, >+ name: "BCM5400", >+ features: MII_GBIT_FEATURES, >+ magic_aneg: 1, >+ ops: &bcm5400_phy_ops >+}; >+ >+/* Broadcom BCM 5401 */ >+static struct mii_phy_ops bcm5401_phy_ops = { >+ init: bcm5401_init, >+ suspend: bcm5401_suspend, >+ setup_aneg: bcm54xx_setup_aneg, >+ setup_forced: bcm54xx_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: bcm54xx_read_link, >+}; >+ >+static struct mii_phy_def bcm5401_phy_def = { >+ phy_id: 0x00206050, >+ phy_id_mask: 0xfffffff0, >+ name: "BCM5401", >+ features: MII_GBIT_FEATURES, >+ magic_aneg: 1, >+ ops: &bcm5401_phy_ops >+}; >+ >+/* Broadcom BCM 5411 */ >+static struct mii_phy_ops bcm5411_phy_ops = { >+ init: bcm5411_init, >+ suspend: bcm5411_suspend, >+ setup_aneg: bcm54xx_setup_aneg, >+ setup_forced: bcm54xx_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: bcm54xx_read_link, >+}; >+ >+static struct mii_phy_def bcm5411_phy_def = { >+ phy_id: 0x00206070, >+ phy_id_mask: 0xfffffff0, >+ name: "BCM5411", >+ features: MII_GBIT_FEATURES, >+ magic_aneg: 1, >+ ops: &bcm5411_phy_ops >+}; >+ >+/* Broadcom BCM 5421 */ >+static struct mii_phy_ops bcm5421_phy_ops = { >+ init: bcm5421_init, >+ suspend: bcm5411_suspend, >+ setup_aneg: bcm54xx_setup_aneg, >+ setup_forced: bcm54xx_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: bcm54xx_read_link, >+}; >+ >+static struct mii_phy_def bcm5421_phy_def = { >+ phy_id: 0x002060e0, >+ phy_id_mask: 0xfffffff0, >+ name: "BCM5421", >+ features: MII_GBIT_FEATURES, >+ magic_aneg: 1, >+ ops: &bcm5421_phy_ops >+}; >+ >+/* Marvell 88E1101 (Apple seem to deal with 2 different revs, >+ * I masked out the 8 last bits to get both, but some specs >+ * would be useful here) --BenH. >+ */ >+static struct mii_phy_ops marvell_phy_ops = { >+ setup_aneg: marvell_setup_aneg, >+ setup_forced: marvell_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: marvell_read_link >+}; >+ >+static struct mii_phy_def marvell_phy_def = { >+ phy_id: 0x01410c00, >+ phy_id_mask: 0xffffff00, >+ name: "Marvell 88E1101", >+ features: MII_GBIT_FEATURES, >+ magic_aneg: 1, >+ ops: &marvell_phy_ops >+}; >+ >+/* Generic implementation for most 10/100 PHYs */ >+static struct mii_phy_ops generic_phy_ops = { >+ setup_aneg: genmii_setup_aneg, >+ setup_forced: genmii_setup_forced, >+ poll_link: genmii_poll_link, >+ read_link: genmii_read_link >+}; >+ >+static struct mii_phy_def genmii_phy_def = { >+ phy_id: 0x00000000, >+ phy_id_mask: 0x00000000, >+ name: "Generic MII", >+ features: MII_BASIC_FEATURES, >+ magic_aneg: 0, >+ ops: &generic_phy_ops >+}; >+ >+static struct mii_phy_def* mii_phy_table[] = { >+ &bcm5201_phy_def, >+ &bcm5221_phy_def, >+ &bcm5400_phy_def, >+ &bcm5401_phy_def, >+ &bcm5411_phy_def, >+ &bcm5421_phy_def, >+ &marvell_phy_def, >+ &genmii_phy_def, >+ NULL >+}; >+ >+int mii_phy_probe(struct mii_phy *phy, int mii_id) >+{ >+ int rc; >+ u32 id; >+ struct mii_phy_def* def; >+ int i; >+ >+ /* We do not reset the mii_phy structure as the driver >+ * may re-probe the PHY regulary >+ */ >+ phy->mii_id = mii_id; >+ >+ /* Take PHY out of isloate mode and reset it. */ >+ rc = reset_one_mii_phy(phy, mii_id); >+ if (rc) >+ goto fail; >+ >+ /* Read ID and find matching entry */ >+ id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)) >+ & 0xfffffff0; >+ for (i=0; (def = mii_phy_table[i]) != NULL; i++) >+ if ((id & def->phy_id_mask) == def->phy_id) >+ break; >+ /* Should never be NULL (we have a generic entry), but... */ >+ if (def == NULL) >+ goto fail; >+ >+ phy->def = def; >+ >+ return 0; >+fail: >+ phy->speed = 0; >+ phy->duplex = 0; >+ phy->pause = 0; >+ phy->advertising = 0; >+ return -ENODEV; >+} >+ >+EXPORT_SYMBOL(mii_phy_probe); >+MODULE_LICENSE("GPL"); >+ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/sungem_phy.h linux-2.4.22-ppc-dev/drivers/net/sungem_phy.h >--- linux-2.4.22-ppc-dev.orig/drivers/net/sungem_phy.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/net/sungem_phy.h 2003-08-25 23:37:55.000000000 +0200 >@@ -0,0 +1,116 @@ >+#ifndef __SUNGEM_PHY_H__ >+#define __SUNGEM_PHY_H__ >+ >+struct mii_phy; >+ >+/* Operations supported by any kind of PHY */ >+struct mii_phy_ops >+{ >+ int (*init)(struct mii_phy *phy); >+ int (*suspend)(struct mii_phy *phy, int wol_options); >+ int (*setup_aneg)(struct mii_phy *phy, u32 advertise); >+ int (*setup_forced)(struct mii_phy *phy, int speed, int fd); >+ int (*poll_link)(struct mii_phy *phy); >+ int (*read_link)(struct mii_phy *phy); >+}; >+ >+/* Structure used to statically define an mii/gii based PHY */ >+struct mii_phy_def >+{ >+ u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ >+ u32 phy_id_mask; /* Significant bits */ >+ u32 features; /* Ethtool SUPPORTED_* defines */ >+ int magic_aneg; /* Autoneg does all speed test for us */ >+ const char* name; >+ const struct mii_phy_ops* ops; >+}; >+ >+/* An instance of a PHY, partially borrowed from mii_if_info */ >+struct mii_phy >+{ >+ struct mii_phy_def* def; >+ int advertising; >+ int mii_id; >+ >+ /* 1: autoneg enabled, 0: disabled */ >+ int autoneg; >+ >+ /* forced speed & duplex (no autoneg) >+ * partner speed & duplex & pause (autoneg) >+ */ >+ int speed; >+ int duplex; >+ int pause; >+ >+ /* Provided by host chip */ >+ struct net_device* dev; >+ int (*mdio_read) (struct net_device *dev, int mii_id, int reg); >+ void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); >+}; >+ >+/* Pass in a struct mii_phy with dev, mdio_read and mdio_write >+ * filled, the remaining fields will be filled on return >+ */ >+extern int mii_phy_probe(struct mii_phy *phy, int mii_id); >+ >+ >+/* MII definitions missing from mii.h */ >+ >+#define BMCR_SPD2 0x0040 /* Gigabit enable (bcm54xx) */ >+#define LPA_PAUSE 0x0400 >+ >+/* More PHY registers (model specific) */ >+ >+/* MII BCM5201 MULTIPHY interrupt register */ >+#define MII_BCM5201_INTERRUPT 0x1A >+#define MII_BCM5201_INTERRUPT_INTENABLE 0x4000 >+ >+#define MII_BCM5201_AUXMODE2 0x1B >+#define MII_BCM5201_AUXMODE2_LOWPOWER 0x0008 >+ >+#define MII_BCM5201_MULTIPHY 0x1E >+ >+/* MII BCM5201 MULTIPHY register bits */ >+#define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 >+#define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 >+ >+/* MII BCM5221 Additional registers */ >+#define MII_BCM5221_TEST 0x1f >+#define MII_BCM5221_TEST_ENABLE_SHADOWS 0x0080 >+#define MII_BCM5221_SHDOW_AUX_STAT2 0x1b >+#define MII_BCM5221_SHDOW_AUX_STAT2_APD 0x0020 >+#define MII_BCM5221_SHDOW_AUX_MODE4 0x1a >+#define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR 0x0004 >+ >+/* MII BCM5400 1000-BASET Control register */ >+#define MII_BCM5400_GB_CONTROL 0x09 >+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 >+ >+/* MII BCM5400 AUXCONTROL register */ >+#define MII_BCM5400_AUXCONTROL 0x18 >+#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 >+ >+/* MII BCM5400 AUXSTATUS register */ >+#define MII_BCM5400_AUXSTATUS 0x19 >+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 >+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 >+ >+/* 1000BT control (Marvell & BCM54xx at least) */ >+#define MII_1000BASETCONTROL 0x09 >+#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 >+#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 >+ >+/* Marvell 88E1011 PHY control */ >+#define MII_M1011_PHY_SPEC_CONTROL 0x10 >+#define MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX 0x20 >+#define MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX 0x40 >+ >+/* Marvell 88E1011 PHY status */ >+#define MII_M1011_PHY_SPEC_STATUS 0x11 >+#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 >+#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 >+#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 >+#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 >+#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 >+ >+#endif /* __SUNGEM_PHY_H__ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/tg3.c linux-2.4.22-ppc-dev/drivers/net/tg3.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/tg3.c 2003-08-27 15:17:58.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/tg3.c 2003-08-25 23:37:25.000000000 +0200 >@@ -145,6 +145,8 @@ > PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, > { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, >+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, > { 0, } > }; > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/tulip/tulip_core.c linux-2.4.22-ppc-dev/drivers/net/tulip/tulip_core.c >--- linux-2.4.22-ppc-dev.orig/drivers/net/tulip/tulip_core.c 2003-08-27 15:17:58.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/tulip/tulip_core.c 2003-08-25 23:37:51.000000000 +0200 >@@ -474,6 +474,15 @@ > } else > tulip_select_media(dev, 1); > >+ /* check for Apple 100BaseTX card and disable loops */ >+ if ((dev->dev_addr[0] == 0x00) && >+ (dev->dev_addr[1] == 0x05) && >+ (dev->dev_addr[2] == 0x02) && >+ (tp->chip_id == DC21140)) { >+ outl(0x10f, ioaddr + CSR12); >+ outl(0x03, ioaddr + CSR12); >+ } >+ > /* Start the chip's Tx to process setup frame. */ > tulip_stop_rxtx(tp); > barrier(); >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/wan/8253x/build linux-2.4.22-ppc-dev/drivers/net/wan/8253x/build >--- linux-2.4.22-ppc-dev.orig/drivers/net/wan/8253x/build 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/net/wan/8253x/build 2003-08-25 23:37:29.000000000 +0200 >@@ -0,0 +1,8 @@ >+cc -g -o 8253xcfg -I. -U__KERNEL__ 8253xcfg.c >+cc -g -o 8253xspeed -I. -U__KERNEL__ 8253xspeed.c >+cc -g -o 8253xmode -I. -U__KERNEL__ 8253xmode.c >+cc -g -o 8253xpeer -I. -U__KERNEL__ 8253xpeer.c >+cc -g -o eprom9050 -I. -U__KERNEL__ eprom9050.c >+ >+ >+ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/wireless/Config.in linux-2.4.22-ppc-dev/drivers/net/wireless/Config.in >--- linux-2.4.22-ppc-dev.orig/drivers/net/wireless/Config.in 2002-11-29 00:53:14.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/net/wireless/Config.in 2003-08-25 23:37:34.000000000 +0200 >@@ -15,6 +15,7 @@ > if [ "$CONFIG_PCI" = "y" ]; then > dep_tristate ' Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL > dep_tristate ' Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL >+ dep_tristate ' Prism II devices connected via a TMD7160 (EXPERIMENTAL)' CONFIG_TMD_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL > fi > > # If Pcmcia is compiled in, offer Pcmcia cards... >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/net/wireless/Makefile linux-2.4.22-ppc-dev/drivers/net/wireless/Makefile >--- linux-2.4.22-ppc-dev.orig/drivers/net/wireless/Makefile 2002-08-03 02:39:44.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/net/wireless/Makefile 2003-08-25 23:37:25.000000000 +0200 >@@ -19,6 +19,7 @@ > obj-$(CONFIG_APPLE_AIRPORT) += airport.o > obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o > obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o >+obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o > > obj-$(CONFIG_AIRO) += airo.o > obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/pci/pci.c linux-2.4.22-ppc-dev/drivers/pci/pci.c >--- linux-2.4.22-ppc-dev.orig/drivers/pci/pci.c 2003-06-13 16:51:35.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/pci/pci.c 2003-08-25 23:37:39.000000000 +0200 >@@ -28,7 +28,7 @@ > #include <asm/page.h> > #include <asm/dma.h> /* isa_dma_bridge_buggy */ > >-#undef DEBUG >+#define DEBUG > > #ifdef DEBUG > #define DBG(x...) printk(x) >@@ -1059,16 +1059,23 @@ > unsigned int pos, reg, next; > u32 l, sz; > struct resource *res; >+ int is_kl = (dev->device == 0x22 && dev->vendor == 0x106b); > >+ if (is_kl) >+ howmany = 1; > for(pos=0; pos<howmany; pos = next) { > next = pos+1; > res = &dev->resource[pos]; > res->name = dev->name; > reg = PCI_BASE_ADDRESS_0 + (pos << 2); > pci_read_config_dword(dev, reg, &l); >- pci_write_config_dword(dev, reg, ~0); >- pci_read_config_dword(dev, reg, &sz); >- pci_write_config_dword(dev, reg, l); >+ if (is_kl) >+ sz = 0x00080000; >+ else { >+ pci_write_config_dword(dev, reg, ~0); >+ pci_read_config_dword(dev, reg, &sz); >+ pci_write_config_dword(dev, reg, l); >+ } > if (!sz || sz == 0xffffffff) > continue; > if (l == 0xffffffff) >@@ -1309,7 +1316,7 @@ > if (!pass) > return max; > pci_read_config_word(dev, PCI_COMMAND, &cr); >- pci_write_config_word(dev, PCI_COMMAND, 0x0000); >+ //pci_write_config_word(dev, PCI_COMMAND, 0x0000); > pci_write_config_word(dev, PCI_STATUS, 0xffff); > > child = pci_add_new_bus(bus, dev, ++max); >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/.version linux-2.4.22-ppc-dev/drivers/sound/.version >--- linux-2.4.22-ppc-dev.orig/drivers/sound/.version 1997-11-10 08:01:54.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/.version 1970-01-01 01:00:00.000000000 +0100 >@@ -1,2 +0,0 @@ >-3.8s >-0x030804 >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/Config.in linux-2.4.22-ppc-dev/drivers/sound/dmasound/Config.in >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/Config.in 2002-02-25 20:38:04.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/Config.in 2003-08-25 23:37:54.000000000 +0200 >@@ -27,13 +27,27 @@ > fi > > # the new dmasound_pmac driver needs access to the i2c bus >+# and nvram. > if [ "$CONFIG_DMASOUND_PMAC" = "y" ] ; then >- define_tristate CONFIG_I2C y >- define_tristate CONFIG_I2C_KEYWEST y >+ if [ "$CONFIG_I2C" != "y" ]; then >+ define_tristate CONFIG_I2C y >+ fi >+ if [ "$CONFIG_I2C_KEYWEST" != "y" ]; then >+ define_tristate CONFIG_I2C_KEYWEST y >+ fi >+ if [ "$CONFIG_NVRAM" != "y" -a "$CONFIG_NVRAM" != "m" ]; then >+ define_tristate CONFIG_NVRAM y >+ fi > else > if [ "$CONFIG_DMASOUND_PMAC" = "m" ] ; then >- define_tristate CONFIG_I2C m >- define_tristate CONFIG_I2C_KEYWEST m >+ if [ "$CONFIG_I2C" != "y" -a "$CONFIG_I2C" != "m" ]; then >+ define_tristate CONFIG_I2C m >+ fi >+ if [ "$CONFIG_I2C_KEYWEST" != "y" -a "$CONFIG_I2C_KEYWEST" != "m" ]; then >+ define_tristate CONFIG_I2C_KEYWEST m >+ fi >+ if [ "$CONFIG_NVRAM" != "y" -a "$CONFIG_NVRAM" != "m" ]; then >+ define_tristate CONFIG_NVRAM y >+ fi > fi > fi >- >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/Makefile linux-2.4.22-ppc-dev/drivers/sound/dmasound/Makefile >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/Makefile 2002-02-25 20:38:04.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/Makefile 2003-08-25 23:37:44.000000000 +0200 >@@ -13,7 +13,8 @@ > > list-multi := dmasound_pmac.o > >-dmasound_pmac-objs := dmasound_awacs.o trans_16.o tas3001c.o dac3550a.o >+dmasound_pmac-objs := dmasound_awacs.o trans_16.o dac3550a.o tas_common.o \ >+ tas3001c.o tas3001c_tables.o tas3004.o tas3004_tables.o > > obj-$(CONFIG_DMASOUND) += dmasound_core.o > obj-$(CONFIG_DMASOUND_ATARI) += dmasound_atari.o >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/awacs_defs.h linux-2.4.22-ppc-dev/drivers/sound/dmasound/awacs_defs.h >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/awacs_defs.h 2002-02-25 20:38:04.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/awacs_defs.h 2003-08-25 23:38:02.000000000 +0200 >@@ -168,8 +168,9 @@ > > #define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */ > >- >+/*******************/ > /* Burgundy values */ >+/*******************/ > > #define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) > #define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) >@@ -232,4 +233,19 @@ > #define DEF_BURGUNDY_ATTENLINEOUT (0xCC) > #define DEF_BURGUNDY_ATTENHP (0xCC) > >+/*********************/ >+/* i2s layout values */ >+/*********************/ >+ >+#define I2S_REG_INT_CTL 0x00 >+#define I2S_REG_SERIAL_FORMAT 0x10 >+#define I2S_REG_CODEC_MSG_OUT 0x20 >+#define I2S_REG_CODEC_MSG_IN 0x30 >+#define I2S_REG_FRAME_COUNT 0x40 >+#define I2S_REG_FRAME_MATCH 0x50 >+#define I2S_REG_DATAWORD_SIZES 0x60 >+#define I2S_REG_PEAKLEVEL_SEL 0x70 >+#define I2S_REG_PEAKLEVEL_IN0 0x80 >+#define I2S_REG_PEAKLEVEL_IN1 0x90 >+ > #endif /* _AWACS_DEFS_H_ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/dmasound_awacs.c linux-2.4.22-ppc-dev/drivers/sound/dmasound/dmasound_awacs.c >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/dmasound_awacs.c 2002-08-03 02:39:44.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/dmasound_awacs.c 2003-08-25 23:38:07.000000000 +0200 >@@ -45,7 +45,14 @@ > * 01/02/2002 [0.7] - BenH > * - all sort of minor bits went in since the latest update, I > * bumped the version number for that reason >-*/ >+ * >+ * 07/26/2002 [0.8] - BenH >+ * - More minor bits since last changelog (I should be more careful >+ * with those) >+ * - Support for snapper & better tumbler integration by Toby Sargeant >+ * - Headphone detect for scremer by Julien Blache >+ * - More tumbler fixed by Andreas Schwab >+ */ > > /* GENERAL FIXME/TODO: check that the assumptions about what is written to > mac-io is valid for DACA & Tumbler. >@@ -88,10 +95,14 @@ > > #include "awacs_defs.h" > #include "dmasound.h" >+#include "tas3001c.h" >+#include "tas3004.h" >+#include "tas_common.h" > > #define DMASOUND_AWACS_REVISION 0 > #define DMASOUND_AWACS_EDITION 7 > >+#define AWACS_SNAPPER 110 /* fake revision # for snapper */ > #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ > #define AWACS_TUMBLER 90 /* fake revision # for tumbler */ > #define AWACS_DACA 80 /* fake revision # for daca (ibook) */ >@@ -102,11 +113,13 @@ > */ > static int awacs_irq, awacs_tx_irq, awacs_rx_irq; > static volatile struct awacs_regs *awacs; >+static volatile u32 *i2s; > static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; > static int awacs_rate_index; > static int awacs_subframe; > static int awacs_spkr_vol; > static struct device_node* awacs_node; >+static struct device_node* i2s_node; > > static char awacs_name[64]; > static int awacs_revision; >@@ -163,6 +176,8 @@ > static int cd_lev = 0x6363 ; /* 99 % */ > static int line_lev = 0 ; > >+static int hdp_connected = 0; >+ > /* > * Stuff for outputting a beep. The values range from -327 to +327 > * so we can multiply by an amplitude in the range 0..100 to get a >@@ -293,19 +308,6 @@ > extern int daca_enter_sleep(void); > extern int daca_leave_sleep(void); > >-extern int tas_init(void); >-extern int tas_cleanup(void); >-extern int tumbler_set_volume(uint left_vol, uint right_vol); >-extern void tumbler_get_volume(uint * left_vol, uint *right_vol); >-extern void tumbler_set_treble(int treble); >-extern void tumbler_get_treble(int *treble); >-extern void tumbler_set_bass(int bass); >-extern void tumbler_get_bass(int *bass); >-extern void tumbler_set_pcm_lvl(int pcm_lvl); >-extern void tumbler_get_pcm_lvl(int *pcm_lvl); >-extern int tumbler_enter_sleep(void); >-extern int tumbler_leave_sleep(void); >- > #define TRY_LOCK() \ > if ((rc = down_interruptible(&dmasound_sem)) != 0) \ > return rc; >@@ -332,7 +334,7 @@ > } > > >-/*** AE - TUMBLER START *********************************************************/ >+/*** AE - TUMBLER / SNAPPER START ************************************************/ > > > int gpio_audio_reset, gpio_audio_reset_pol; >@@ -394,17 +396,22 @@ > return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0); > } > >+/* >+ * Headphone interrupt via GPIO (Tumbler, Snapper, DACA) >+ */ > static void > headphone_intr(int irq, void *devid, struct pt_regs *regs) > { > if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) { > printk(KERN_INFO "Audio jack plugged, muting speakers.\n"); >- write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); > write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); >+ write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); >+ tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0); > } else { > printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n"); > write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); > write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); >+ tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0); > } > } > >@@ -412,7 +419,7 @@ > /* Initialize tumbler */ > > static int >-awacs_tumbler_init(void) >+tas_dmasound_init(void) > { > setup_audio_gpio( > "audio-hw-reset", >@@ -469,15 +476,124 @@ > > > static int >-awacs_tumbler_cleanup(void) >+tas_dmasound_cleanup(void) > { > if (gpio_headphone_irq) > free_irq(gpio_headphone_irq, 0); > return 0; > } > >+/* We don't support 48k yet */ >+static int tas_freqs[1] = { 44100 } ; >+static int tas_freqs_ok[1] = { 1 } ; > >-/*** AE - TUMBLER END *********************************************************/ >+/* don't know what to do really - just have to leave it where >+ * OF left things >+*/ >+ >+static int >+tas_set_frame_rate(void) >+{ >+ if (i2s) { >+ out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); >+ out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); >+ } >+ dmasound.hard.speed = 44100 ; >+ awacs_rate_index = 0 ; >+ return 44100 ; >+} >+ >+static int >+tas_mixer_ioctl(u_int cmd, u_long arg) >+{ >+ int data; >+ int rc; >+ >+ rc=tas_device_ioctl(cmd, arg); >+ if (rc != -EINVAL) { >+ return rc; >+ } >+ >+ if ((cmd & ~0xff) == MIXER_WRITE(0) && >+ tas_supported_mixers() & (1<<(cmd & 0xff))) { >+ rc = get_user(data, (int *)(arg)); >+ if (rc<0) return rc; >+ tas_set_mixer_level(cmd & 0xff, data); >+ tas_get_mixer_level(cmd & 0xff, &data); >+ return ioctl_return2((int *)(arg), data); >+ } >+ if ((cmd & ~0xff) == MIXER_READ(0) && >+ tas_supported_mixers() & (1<<(cmd & 0xff))) { >+ tas_get_mixer_level(cmd & 0xff, &data); >+ return ioctl_return2((int *)(arg), data); >+ } >+ >+ switch(cmd) { >+ case SOUND_MIXER_READ_DEVMASK: >+ data = tas_supported_mixers() | SOUND_MASK_SPEAKER; >+ rc = IOCTL_OUT(arg, data); >+ break; >+ case SOUND_MIXER_READ_STEREODEVS: >+ data = tas_stereo_mixers(); >+ rc = IOCTL_OUT(arg, data); >+ break; >+ case SOUND_MIXER_READ_CAPS: >+ rc = IOCTL_OUT(arg, 0); >+ break; >+ case SOUND_MIXER_READ_RECMASK: >+ data = 0; >+ rc = IOCTL_OUT(arg, data); >+ break; >+ case SOUND_MIXER_READ_RECSRC: >+ data = 0; >+ rc = IOCTL_OUT(arg, data); >+ break; >+ case SOUND_MIXER_WRITE_RECSRC: >+ IOCTL_IN(arg, data); >+ data =0; >+ rc = IOCTL_OUT(arg, data); >+ break; >+ case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */ >+ IOCTL_IN(arg, data); >+ beep_vol = data & 0xff; >+ /* fall through */ >+ case SOUND_MIXER_READ_SPEAKER: >+ rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol); >+ break; >+ case SOUND_MIXER_OUTMASK: >+ case SOUND_MIXER_OUTSRC: >+ default: >+ rc = -EINVAL; >+ } >+ >+ return rc; >+} >+ >+static void __init >+tas_init_frame_rates(unsigned int *prop, unsigned int l) >+{ >+ int i ; >+ if (prop) { >+ for (i=0; i<1; i++) >+ tas_freqs_ok[i] = 0; >+ for (l /= sizeof(int); l > 0; --l) { >+ unsigned int r = *prop++; >+ /* Apple 'Fixed' format */ >+ if (r >= 0x10000) >+ r >>= 16; >+ for (i = 0; i < 1; ++i) { >+ if (r == tas_freqs[i]) { >+ tas_freqs_ok[i] = 1; >+ break; >+ } >+ } >+ } >+ } >+ /* else we assume that all the rates are available */ >+} >+ >+ >+/*** AE - TUMBLER / SNAPPER END ************************************************/ > > > >@@ -509,8 +625,10 @@ > > static int __init PMacIrqInit(void) > { >- if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0) >- || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0) >+ if (awacs) >+ if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0)) >+ return 0; >+ if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0) > || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", 0)) > return 0; > return 1; >@@ -523,23 +641,28 @@ > DBDMA_DO_STOP(awacs_txdma); > DBDMA_DO_STOP(awacs_rxdma); > >- /* disable interrupts from awacs interface */ >- out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); >- >+ if (awacs) >+ /* disable interrupts from awacs interface */ >+ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); >+ > /* Switch off the sound clock */ > pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); > /* Make sure proper bits are set on pismo & tipb */ >- if (machine_is_compatible("PowerBook3,1") || >- machine_is_compatible("PowerBook3,2")) { >+ if ((machine_is_compatible("PowerBook3,1") || >+ machine_is_compatible("PowerBook3,2")) && awacs) { > awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; > awacs_write(MASK_ADDR1 | awacs_reg[1]); > wait_ms(200); > } >- free_irq(awacs_irq, 0); >+ if (awacs) >+ free_irq(awacs_irq, 0); > free_irq(awacs_tx_irq, 0); > free_irq(awacs_rx_irq, 0); >- /* all OF versions I've seen use this value */ >- iounmap((void *)awacs); >+ >+ if (awacs) >+ iounmap((void *)awacs); >+ if (i2s) >+ iounmap((void *)i2s); > iounmap((void *)awacs_txdma); > iounmap((void *)awacs_rxdma); > >@@ -555,7 +678,9 @@ > kfree(beep_dbdma_cmd_space); > if (beep_buf) { > kfree(beep_buf); >+#ifdef CONFIG_VT > kd_mksound = orig_mksound; >+#endif > } > #ifdef CONFIG_PMAC_PBOOK > pmu_unregister_sleep_notifier(&awacs_sleep_notifier); >@@ -569,26 +694,16 @@ > DBDMA_DO_STOP(awacs_txdma); > } > >-static int tumbler_freqs[2] = { 48000, 44100 } ; >-static int tumbler_freqs_ok[2] = { 1, 1 } ; >- >-/* don't know what to do really - just have to leave it where >- * OF left things >-*/ >- >-static int tumbler_set_frame_rate(void) >-{ >- dmasound.hard.speed = 44100 ; >- awacs_rate_index = 0 ; >- return 44100 ; >-} >- > /* don't know what to do really - just have to leave it where > * OF left things > */ > > static int daca_set_frame_rate(void) > { >+ if (i2s) { >+ out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); >+ out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); >+ } > dmasound.hard.speed = 44100 ; > awacs_rate_index = 0 ; > return 44100 ; >@@ -599,7 +714,8 @@ > }; > static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; > >-static int awacs_set_frame_rate(int desired, int catch_r) >+static int >+awacs_set_frame_rate(int desired, int catch_r) > { > int tolerance, i = 8 ; > /* >@@ -623,13 +739,9 @@ > return dmasound.hard.speed; > } > >-static int burgundy_frame_rates = 1 ; >-static int burgundy_set_frame_rate(void) >+static int >+burgundy_set_frame_rate(void) > { >-#ifdef DEBUG_DMASOUND >-if (burgundy_frame_rates > 1) >- printk("dmasound_pmac: warning Burgundy had more than one frame rate\n"); >-#endif > awacs_rate_index = 0 ; > awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ; > /* XXX disable error interrupt on burgundy for now */ >@@ -637,24 +749,24 @@ > return 44100 ; > } > >-static int set_frame_rate(int desired, int catch_r) >+static int >+set_frame_rate(int desired, int catch_r) > { > switch (awacs_revision) { > case AWACS_BURGUNDY: >- dmasound.hard.speed = >- burgundy_set_frame_rate(); >+ dmasound.hard.speed = burgundy_set_frame_rate(); > break ; > case AWACS_TUMBLER: >- dmasound.hard.speed = >- tumbler_set_frame_rate(); >+ case AWACS_SNAPPER: >+ dmasound.hard.speed = tas_set_frame_rate(); > break ; > case AWACS_DACA: > dmasound.hard.speed = > daca_set_frame_rate(); > break ; > default: >- dmasound.hard.speed = >- awacs_set_frame_rate(desired, catch_r); >+ dmasound.hard.speed = awacs_set_frame_rate(desired, >+ catch_r); > break ; > } > return dmasound.hard.speed ; >@@ -704,11 +816,13 @@ > dmasound.trans_write = &transAwacsExpand; > dmasound.trans_read = &transAwacsNormalRead; > >- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) >- out_le32(&awacs->byteswap, BS_VAL); >- else >- out_le32(&awacs->byteswap, 0); >- >+ if (awacs) { >+ if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) >+ out_le32(&awacs->byteswap, BS_VAL); >+ else >+ out_le32(&awacs->byteswap, 0); >+ } >+ > expand_bal = -dmasound.soft.speed; > } > >@@ -793,7 +907,20 @@ > > static int PMacSetVolume(int volume) > { >- return awacs_volume_setter(volume, 2, MASK_AMUTE, 6); >+ printk(KERN_WARNING "Bogus call to PMacSetVolume !\n"); >+ return 0; >+} >+ >+static void awacs_setup_for_beep(int speed) >+{ >+ out_le32(&awacs->control, >+ (in_le32(&awacs->control) & ~0x1f00) >+ | ((speed > 0 ? speed : awacs_rate_index) << 8)); >+ >+ if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1) >+ out_le32(&awacs->byteswap, BS_VAL); >+ else >+ out_le32(&awacs->byteswap, 0); > } > > static void __PMacPlay(void) >@@ -816,15 +943,8 @@ > out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); > while ( (in_le32(&awacs_txdma->status) & RUN) && count--) > udelay(1); >- /* FIXME: check that this is OK for other chip sets */ >- out_le32(&awacs->control, >- (in_le32(&awacs->control) & ~0x1f00) >- | (awacs_rate_index << 8)); >- >- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) >- out_le32(&awacs->byteswap, BS_VAL); >- else >- out_le32(&awacs->byteswap, 0); >+ if (awacs) >+ awacs_setup_for_beep(-1); > out_le32(&awacs_txdma->cmdptr, > virt_to_bus(&(awacs_tx_cmds[next_frg]))); > >@@ -925,6 +1045,7 @@ > { > int i = write_sq.front; > int stat; >+ int i_nowrap = write_sq.front; > volatile struct dbdma_cmd *cp; > /* != 0 when we are dealing with a DEAD xfer */ > static int emergency_in_use = 0 ; >@@ -981,6 +1102,7 @@ > emergency_in_use = 0 ; /* done that */ > --write_sq.count; > --write_sq.active; >+ i_nowrap++; > if (++i >= write_sq.max_count) > i = 0; > } >@@ -993,7 +1115,7 @@ > } > > /* if we used some data up then wake the writer to supply some more*/ >- if (i != write_sq.front) >+ if (i_nowrap != write_sq.front) > WAKE_UP(write_sq.action_queue); > write_sq.front = i; > >@@ -1090,9 +1212,26 @@ > pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs) > { > int ctrl = in_le32(&awacs->control); >+ int status = in_le32(&awacs->codec_stat); >+ int r1; > >- if (ctrl & MASK_PORTCHG) { >- /* do something when headphone is plugged/unplugged? */ >+ if (ctrl & MASK_PORTCHG) { >+ /* tested on Screamer, should work on others too */ >+ if (awacs_revision == AWACS_SCREAMER) { >+ if (((status & MASK_HDPCONN) >> 3) && (hdp_connected == 0)) { >+ hdp_connected = 1; >+ >+ r1 = awacs_reg[1] | MASK_SPKMUTE; >+ awacs_reg[1] = r1; >+ awacs_write(r1 | MASK_ADDR_MUTE); >+ } else if (((status & MASK_HDPCONN) >> 3 == 0) && (hdp_connected == 1)) { >+ hdp_connected = 0; >+ >+ r1 = awacs_reg[1] & ~MASK_SPKMUTE; >+ awacs_reg[1] = r1; >+ awacs_write(r1 | MASK_ADDR_MUTE); >+ } >+ } > } > if (ctrl & MASK_CNTLERR) { > int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; >@@ -1108,7 +1247,7 @@ > awacs_write(int val) > { > int count = 300 ; >- if (awacs_revision >= AWACS_DACA) >+ if (awacs_revision >= AWACS_DACA || !awacs) > return ; > > while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) >@@ -1131,14 +1270,8 @@ > out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); > while ((in_le32(&awacs_txdma->status) & RUN) && count--) > udelay(1); >- /* FIXME: check this is OK for DACA, Tumbler */ >- out_le32(&awacs->control, >- (in_le32(&awacs->control) & ~0x1f00) >- | (awacs_rate_index << 8)); >- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) >- out_le32(&awacs->byteswap, BS_VAL); >- else >- out_le32(&awacs->byteswap, 0); >+ if (awacs) >+ awacs_setup_for_beep(-1); > beep_playing = 0; > } > restore_flags(flags); >@@ -1233,11 +1366,8 @@ > out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); > while ((in_le32(&awacs_txdma->status) & RUN) && count--) > udelay(1); /* timeout > 2 samples at lowest rate*/ >- /* FIXME: check this is OK on DACA, Tumbler */ >- out_le32(&awacs->control, >- (in_le32(&awacs->control) & ~0x1f00) >- | (beep_speed << 8)); >- out_le32(&awacs->byteswap, 0); /* force BE */ >+ if (awacs) >+ awacs_setup_for_beep(beep_speed); > out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); > (void)in_le32(&awacs_txdma->status); > out_le32(&awacs_txdma->control, RUN | (RUN << 16)); >@@ -1263,10 +1393,12 @@ > awacs_write(awacs_reg[1] + MASK_ADDR1); > awacs_write(awacs_reg[7] + MASK_ADDR7); > } >- if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) >- out_le32(&awacs->byteswap, BS_VAL); >- else >- out_le32(&awacs->byteswap, 0); >+ if (awacs) { >+ if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) >+ out_le32(&awacs->byteswap, BS_VAL); >+ else >+ out_le32(&awacs->byteswap, 0); >+ } > } > > #ifdef CONFIG_PMAC_PBOOK >@@ -1293,9 +1425,18 @@ > /* stop rx - if going - a bit of a daft user... but */ > out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16)); > /* deny interrupts */ >+ if (awacs) >+ disable_irq(awacs_irq); >+ disable_irq(awacs_tx_irq); >+ disable_irq(awacs_rx_irq); >+ /* Chip specific sleep code */ > switch (awacs_revision) { > case AWACS_TUMBLER: >- tumbler_enter_sleep(); /* Stub for now */ >+ case AWACS_SNAPPER: >+ write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); >+ write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); >+ tas_enter_sleep(); >+ write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); > break ; > case AWACS_DACA: > daca_enter_sleep(); >@@ -1308,17 +1449,14 @@ > out_le32(&awacs->control, 0x11) ; > break ; > } >- disable_irq(awacs_irq); >- disable_irq(awacs_tx_irq); >- disable_irq(awacs_rx_irq); > /* Disable sound clock */ > pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); > /* According to Darwin, we do that after turning off the sound > * chip clock. All this will have to be cleaned up once we properly > * parse the OF sound-objects > */ >- if (machine_is_compatible("PowerBook3,1") || >- machine_is_compatible("PowerBook3,2")) { >+ if ((machine_is_compatible("PowerBook3,1") || >+ machine_is_compatible("PowerBook3,2")) && awacs) { > awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; > awacs_write(MASK_ADDR1 | awacs_reg[1]); > wait_ms(200); >@@ -1327,8 +1465,8 @@ > case PBOOK_WAKE: > /* Enable sound clock */ > pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1); >- if (machine_is_compatible("PowerBook3,1") || >- machine_is_compatible("PowerBook3,2")) { >+ if ((machine_is_compatible("PowerBook3,1") || >+ machine_is_compatible("PowerBook3,2")) && awacs) { > wait_ms(100); > awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1); > awacs_write(MASK_ADDR1 | awacs_reg[1]); >@@ -1338,8 +1476,15 @@ > /* restore settings */ > switch (awacs_revision) { > case AWACS_TUMBLER: >+ case AWACS_SNAPPER: >+ write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); >+ write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); >+ write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); >+ wait_ms(100); >+ write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); >+ wait_ms(150); >+ tas_leave_sleep(); /* Stub for now */ > headphone_intr(0,0,0); >- tumbler_leave_sleep(); /* Stub for now */ > break; > case AWACS_DACA: > wait_ms(10); /* Check this !!! */ >@@ -1354,17 +1499,20 @@ > break ; > } > /* Recalibrate chip */ >- if (awacs_revision == AWACS_SCREAMER) >+ if (awacs_revision == AWACS_SCREAMER && awacs) > awacs_recalibrate(); > /* Make sure dma is stopped */ > PMacSilence(); >- enable_irq(awacs_irq); >+ if (awacs) >+ enable_irq(awacs_irq); > enable_irq(awacs_tx_irq); > enable_irq(awacs_rx_irq); >- /* OK, allow ints back again */ >- out_le32(&awacs->control, MASK_IEPC >- | (awacs_rate_index << 8) | 0x11 >- | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); >+ if (awacs) { >+ /* OK, allow ints back again */ >+ out_le32(&awacs->control, MASK_IEPC >+ | (awacs_rate_index << 8) | 0x11 >+ | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); >+ } > if (macio_base && is_pbook_g3) { > /* FIXME: should restore the setup we had...*/ > out_8(macio_base + 0x37, 3); >@@ -1952,7 +2100,7 @@ > case SOUND_MIXER_READ_SPEAKER: > data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); > data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); >- rc = IOCTL_OUT(arg, ~data); >+ rc = IOCTL_OUT(arg, (~data) & 0x0000ffff); > break; > case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ > IOCTL_IN(arg, data); >@@ -2007,89 +2155,6 @@ > return rc; > } > >-static int tumbler_mixer_ioctl(u_int cmd, u_long arg) >-{ >- int data; >- int rc; >- >- /* We are, we are, we are... Tumbler (and very dumb) */ >- /* Ok, we're not THAT dumb anymore, but still pretty dumb :-) */ >- >- switch(cmd) { >- case SOUND_MIXER_READ_DEVMASK: >- data = SOUND_MASK_VOLUME | SOUND_MASK_ALTPCM | >- SOUND_MASK_BASS | SOUND_MASK_TREBLE | >- SOUND_MASK_PCM; >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_READ_RECMASK: >- data = 0; >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_READ_RECSRC: >- data = 0; >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_WRITE_RECSRC: >- IOCTL_IN(arg, data); >- data =0; >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_READ_STEREODEVS: >- data = SOUND_MASK_VOLUME | SOUND_MASK_PCM; >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_READ_CAPS: >- rc = IOCTL_OUT(arg, 0); >- break; >- case SOUND_MIXER_WRITE_BASS: >- IOCTL_IN(arg, data); >- tumbler_set_bass(data); >- /* Fall through */ >- case SOUND_MIXER_READ_BASS: >- tumbler_get_bass(&data); >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_WRITE_TREBLE: >- IOCTL_IN(arg, data); >- tumbler_set_treble(data); >- /* Fall through */ >- case SOUND_MIXER_READ_TREBLE: >- tumbler_get_treble(&data); >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_WRITE_PCM: >- IOCTL_IN(arg, data); >- tumbler_set_pcm_lvl(data); >- /* Fall through */ >- case SOUND_MIXER_READ_PCM: >- tumbler_get_pcm_lvl(&data); >- IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_WRITE_VOLUME: >- IOCTL_IN(arg, data); >- tumbler_set_volume(data, data); >- /* Fall through */ >- case SOUND_MIXER_READ_VOLUME: >- tumbler_get_volume(& data, &data); >- rc = IOCTL_OUT(arg, data); >- break; >- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ >- IOCTL_IN(arg, data); >- beep_vol = data & 0xff; >- /* fall through */ >- case SOUND_MIXER_READ_ALTPCM: >- rc = IOCTL_OUT(arg, beep_vol); >- break; >- case SOUND_MIXER_OUTMASK: >- case SOUND_MIXER_OUTSRC: >- default: >- rc = -EINVAL; >- } >- >- return rc; >-} >- > static int daca_mixer_ioctl(u_int cmd, u_long arg) > { > int data; >@@ -2154,7 +2219,8 @@ > rc = daca_mixer_ioctl(cmd, arg); > break; > case AWACS_TUMBLER: >- rc = tumbler_mixer_ioctl(cmd, arg); >+ case AWACS_SNAPPER: >+ rc = tas_mixer_ioctl(cmd, arg); > break ; > default: /* ;-)) */ > rc = awacs_mixer_ioctl(cmd, arg); >@@ -2171,7 +2237,9 @@ > case AWACS_TUMBLER: > printk("AE-Init tumbler mixer\n"); > break ; >- >+ case AWACS_SNAPPER: >+ printk("AE-Init snapper mixer\n"); >+ break ; > case AWACS_DACA: > case AWACS_BURGUNDY: > break ; /* don't know yet */ >@@ -2362,12 +2430,12 @@ > len += sprintf(b,"44100 ") ; > break ; > case AWACS_TUMBLER: >- for (i=0; i<2; i++){ >- if (tumbler_freqs_ok[i]) >- len += sprintf(b+len,"%d ", tumbler_freqs[i]) ; >+ case AWACS_SNAPPER: >+ for (i=0; i<1; i++){ >+ if (tas_freqs_ok[i]) >+ len += sprintf(b+len,"%d ", tas_freqs[i]) ; > } > break ; >- > case AWACS_AWACS: > case AWACS_SCREAMER: > default: >@@ -2469,8 +2537,8 @@ > code that looks for chip properties knows how to go about it. > */ > >-static struct device_node >-__init *get_snd_io_node(void) >+static struct device_node* __init >+get_snd_io_node(void) > { > struct device_node *np = NULL; > >@@ -2491,7 +2559,7 @@ > * this seems to be what iBooks (& Tumbler) have. > */ > if (np == NULL) >- np = find_devices("i2s-a"); >+ np = i2s_node = find_devices("i2s-a"); > > /* if we didn't find this - perhaps we are on an early model > * which _only_ has an 'awacs' node >@@ -2511,8 +2579,8 @@ > we have to deduce the info other ways for these. > */ > >-static struct device_node >-__init *get_snd_info_node(struct device_node *io) >+static struct device_node* __init >+get_snd_info_node(struct device_node *io) > { > struct device_node *info; > >@@ -2526,8 +2594,8 @@ > /* Find out what type of codec we have. > */ > >-static int >-__init get_codec_type(struct device_node *info) >+static int __init >+get_codec_type(struct device_node *info) > { > /* already set if pre-davbus model and info will be NULL */ > int codec = awacs_revision ; >@@ -2544,14 +2612,16 @@ > codec = AWACS_DACA; > if (device_is_compatible(info, "tumbler")) > codec = AWACS_TUMBLER; >+ if (device_is_compatible(info, "snapper")) >+ codec = AWACS_SNAPPER; > } > return codec ; > } > > /* find out what type, if any, of expansion card we have > */ >-static void >-__init get_expansion_type(void) >+static void __init >+get_expansion_type(void) > { > if (find_devices("perch") != NULL) > has_perch = 1; >@@ -2569,8 +2639,8 @@ > * Set dmasound.mach.max_dsp_rate on the basis of these routines. > */ > >-static void >-__init init_awacs_frame_rates(unsigned int *prop, unsigned int l) >+static void __init >+awacs_init_frame_rates(unsigned int *prop, unsigned int l) > { > int i ; > if (prop) { >@@ -2592,31 +2662,8 @@ > /* else we assume that all the rates are available */ > } > >-static void >-__init init_tumbler_frame_rates(unsigned int *prop, unsigned int l) >-{ >- int i ; >- if (prop) { >- for (i=0; i<2; i++) >- tumbler_freqs_ok[i] = 0; >- for (l /= sizeof(int); l > 0; --l) { >- unsigned int r = *prop++; >- /* Apple 'Fixed' format */ >- if (r >= 0x10000) >- r >>= 16; >- for (i = 0; i < 2; ++i) { >- if (r == tumbler_freqs[i]) { >- tumbler_freqs_ok[i] = 1; >- break; >- } >- } >- } >- } >- /* else we assume that all the rates are available */ >-} >- >-static void >-__init init_burgundy_frame_rates(unsigned int *prop, unsigned int l) >+static void __init >+burgundy_init_frame_rates(unsigned int *prop, unsigned int l) > { > int temp[9] ; > int i = 0 ; >@@ -2641,8 +2688,8 @@ > #endif > } > >-static void >-__init init_daca_frame_rates(unsigned int *prop, unsigned int l) >+static void __init >+daca_init_frame_rates(unsigned int *prop, unsigned int l) > { > int temp[9] ; > int i = 0 ; >@@ -2668,21 +2715,22 @@ > #endif > } > >-static void >-__init init_frame_rates(unsigned int *prop, unsigned int l) >+static void __init >+init_frame_rates(unsigned int *prop, unsigned int l) > { >- switch (awacs_revision){ >+ switch (awacs_revision) { > case AWACS_TUMBLER: >- init_tumbler_frame_rates(prop, l); >+ case AWACS_SNAPPER: >+ tas_init_frame_rates(prop, l); > break ; > case AWACS_DACA: >- init_daca_frame_rates(prop, l); >+ daca_init_frame_rates(prop, l); > break ; > case AWACS_BURGUNDY: >- init_burgundy_frame_rates(prop, l); >+ burgundy_init_frame_rates(prop, l); > break ; >- default: /* ;-))) */ >- init_awacs_frame_rates(prop, l); >+ default: >+ awacs_init_frame_rates(prop, l); > break ; > } > } >@@ -2690,11 +2738,11 @@ > /* find things/machines that can't do mac-io byteswap > */ > >-static void >-__init set_hw_byteswap(struct device_node *io) >+static void __init >+set_hw_byteswap(struct device_node *io) > { > struct device_node *mio ; >- unsigned int *p, kl = 0 ; >+ unsigned int kl = 0 ; > > /* if seems that Keylargo can't byte-swap */ > >@@ -2741,9 +2789,11 @@ > if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ; > return -ENOMEM ; > } >+#ifdef CONFIG_VT > /* OK, we should be safe to claim the mksound vector now */ > orig_mksound = kd_mksound; > kd_mksound = awacs_mksound; >+#endif > return 0 ; > } > >@@ -2839,23 +2889,26 @@ > } > > /* all OF versions I've seen use this value */ >- awacs = (volatile struct awacs_regs *) >- ioremap(io->addrs[0].address, 0x1000); >+ if (i2s_node) >+ i2s = (u32 *)ioremap(io->addrs[0].address, 0x1000); >+ else >+ awacs = (volatile struct awacs_regs *) >+ ioremap(io->addrs[0].address, 0x1000); > awacs_txdma = (volatile struct dbdma_regs *) > ioremap(io->addrs[1].address, 0x100); > awacs_rxdma = (volatile struct dbdma_regs *) > ioremap(io->addrs[2].address, 0x100); > >-#ifdef CONFIG_PMAC_PBOOK > /* first of all make sure that the chip is powered up....*/ > pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1); >- if (awacs_revision == AWACS_SCREAMER) >+ if (awacs_revision == AWACS_SCREAMER && awacs) > awacs_recalibrate(); >-#endif >+ > awacs_irq = io->intrs[0].line; > awacs_tx_irq = io->intrs[1].line; > awacs_rx_irq = io->intrs[2].line; > >+ /* Hack for legacy crap that will be killed someday */ > awacs_node = io; > > /* if we have an awacs or screamer - probe the chip to make >@@ -2906,8 +2959,9 @@ > /* if it's there use it to set up frame rates */ > init_frame_rates(prop, l) ; > } >- >- out_le32(&awacs->control, 0x11); /* set everything quiesent */ >+ >+ if (awacs) >+ out_le32(&awacs->control, 0x11); /* set everything quiesent */ > > set_hw_byteswap(io) ; /* figure out if the h/w can do it */ > >@@ -2942,9 +2996,20 @@ > #ifdef CONFIG_KMOD > request_module("i2c-keywest"); > #endif /* CONFIG_KMOD */ >- awacs_tumbler_init(); >- tas_init(); >+ tas_register_driver(&tas3001c_hooks); >+ tas_init(I2C_DRIVERID_TAS3001C, I2C_DRIVERNAME_TAS3001C); >+ tas_dmasound_init(); >+ tas_post_init(); > break ; >+ case AWACS_SNAPPER: >+#ifdef CONFIG_KMOD >+ request_module("i2c-keywest"); >+#endif /* CONFIG_KMOD */ >+ tas_register_driver(&tas3004_hooks); >+ tas_init(I2C_DRIVERID_TAS3004,I2C_DRIVERNAME_TAS3004); >+ tas_dmasound_init(); >+ tas_post_init(); >+ break; > case AWACS_DACA: > #ifdef CONFIG_KMOD > request_module("i2c-keywest"); >@@ -3028,11 +3093,15 @@ > dmasound.mach.hardware_afmts = AFMT_S16_BE ; > > /* shut out chips that do output only. >- may need to extend this to machines which have no inputs - even tho' >- they use screamer - IIRC one of the powerbooks is like this. >- */ >+ * may need to extend this to machines which have no inputs - even tho' >+ * they use screamer - IIRC one of the powerbooks is like this. >+ * >+ * FIXME: Actually, some TUMBLER and SNAPPER do have inputs... >+ */ > >- if (awacs_revision != AWACS_TUMBLER && awacs_revision != AWACS_DACA) { >+ if (awacs_revision != AWACS_TUMBLER && >+ awacs_revision != AWACS_SNAPPER && >+ awacs_revision != AWACS_DACA) { > dmasound.mach.capabilities = DSP_CAP_DUPLEX ; > dmasound.mach.record = PMacRecord ; > } >@@ -3050,6 +3119,9 @@ > case AWACS_TUMBLER: > sprintf(awacs_name, "PowerMac Tumbler ") ; > break ; >+ case AWACS_SNAPPER: >+ sprintf(awacs_name, "PowerMac Snapper ") ; >+ break ; > case AWACS_SCREAMER: > sprintf(awacs_name, "PowerMac Screamer ") ; > break ; >@@ -3066,7 +3138,8 @@ > { > switch (awacs_revision) { > case AWACS_TUMBLER: >- awacs_tumbler_cleanup(); >+ case AWACS_SNAPPER: >+ tas_dmasound_cleanup(); > tas_cleanup(); > break ; > case AWACS_DACA: >@@ -3081,3 +3154,10 @@ > > module_init(dmasound_awacs_init); > module_exit(dmasound_awacs_cleanup); >+/* >+ * Local Variables: >+ * tab-width: 8 >+ * indent-tabs-mode: t >+ * c-basic-offset: 8 >+ * End: >+ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3001c.c linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3001c.c >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3001c.c 2002-02-25 20:38:05.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3001c.c 2003-08-25 23:37:29.000000000 +0200 >@@ -1,38 +1,17 @@ > /* >- * Driver for the i2c/i2s based TA3001C sound chip used >- * on some Apple hardware. Also known as "tumbler". >+ * Driver for the i2c/i2s based TA3004 sound chip used >+ * on some Apple hardware. Also known as "snapper". > * >- * This file is subject to the terms and conditions of the GNU General Public >- * License. See the file COPYING in the main directory of this archive >- * for more details. >- * >- * Modified by Christopher C. Chimelis <chris@debian.org>: >+ * Tobias Sargeant <tobias.sargeant@bigpond.com> >+ * Based upon, tas3001c.c by Christopher C. Chimelis <chris@debian.org>: > * > * TODO: > * ----- >- * * Enable DRC since the TiBook speakers are less than good > * * Enable control over input line 2 (is this connected?) >- * * Play with the dual six-stage cascading biquad filtering to see how >- * we can use it to our advantage (currently not implemented) >- * * Reorganise driver a bit to make it cleaner and easier to work with >- * (read: use the header file more :-P) >- * * Implement sleep support >- * >- * Version 0.4: >- * ------------ >- * * Balance control finally works (can someone document OSS better please?) >- * * Moved to a struct for common values referenced in the driver >- * * Put stubs in for sleep/wake-up support for now. This will take some >- * experimentation to make sure that the timing is right, since the >- * TAS hardware requires specific timing while enabling low-power mode. >- * I may cheat for now and just reset the chip on wake-up, but I'd rather >- * not if I don't have to. >- * >- * Version 0.3: >- * ------------ >- * * Fixed volume control >- * * Added bass and treble control >- * * Added PCM line level control (mixer 1 in the TAS manual) >+ * * Implement sleep support (at least mute everything and >+ * * set gains to minimum during sleep) >+ * * Look into some of Darwin's tweaks regarding the mute >+ * * lines (delays & different behaviour on some HW) > * > */ > >@@ -45,403 +24,854 @@ > #include <linux/types.h> > #include <linux/i2c.h> > #include <linux/init.h> >+#include <linux/soundcard.h> > #include <asm/uaccess.h> > #include <asm/errno.h> > #include <asm/io.h> > #include <asm/prom.h> > > #include "dmasound.h" >+#include "tas_common.h" > #include "tas3001c.h" > >-#define I2C_DRIVERID_TAS (0xFEBA) >+#include "tas_ioctl.h" > >-#define TAS_VERSION "0.3" >-#define TAS_DATE "20011214" >+#define TAS3001C_BIQUAD_FILTER_COUNT 6 >+#define TAS3001C_BIQUAD_CHANNEL_COUNT 2 > >-#define TAS_SETTING_MAX 100 >+#define VOL_DEFAULT (100 * 4 / 5) >+#define INPUT_DEFAULT (100 * 4 / 5) >+#define BASS_DEFAULT (100 / 2) >+#define TREBLE_DEFAULT (100 / 2) >+ >+struct tas3001c_data_t { >+ struct tas_data_t super; >+ int device_id; >+ int output_id; >+ int speaker_id; >+ struct tas_drce_t drce_state; >+}; > >-#define VOL_DEFAULT (((((TAS_SETTING_MAX*4)/5)<<0)<<8) | (((TAS_SETTING_MAX*4)/5)<<0)) >-#define INPUT_DEFAULT (((TAS_SETTING_MAX*4)/5)<<0) >-#define BASS_DEFAULT ((TAS_SETTING_MAX/2)<<0) >-#define TREBLE_DEFAULT ((TAS_SETTING_MAX/2)<<0) > >-static struct i2c_client * tumbler_client = NULL; >+static const union tas_biquad_t >+tas3001c_eq_unity={ >+ buf: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } >+}; > >-int tumbler_enter_sleep(void); >-int tumbler_leave_sleep(void); > >-static int tas_attach_adapter(struct i2c_adapter *adapter); >-static int tas_detect_client(struct i2c_adapter *adapter, int address); >-static int tas_detach_client(struct i2c_client *client); >+static inline unsigned char db_to_regval(short db) { >+ int r=0; > >-/* Unique ID allocation */ >-static int tas_id; >-static int tas_initialized; >+ r=(db+0x59a0) / 0x60; > >-static struct device_node* tas_node; >-static u8 tas_i2c_address = 0x34; >+ if (r < 0x91) return 0x91; >+ if (r > 0xef) return 0xef; >+ return r; >+} > >-struct tas_data_t { >- uint left_vol; /* left volume */ >- uint right_vol; /* right volume */ >- uint treble; /* treble */ >- uint bass; /* bass */ >- uint pcm_level; /* pcm level */ >-}; >+static inline short quantize_db(short db) { >+ return db_to_regval(db) * 0x60 - 0x59a0; >+} > >-struct i2c_driver tas_driver = { >- name: "TAS3001C driver V 0.3", >- id: I2C_DRIVERID_TAS, >- flags: I2C_DF_NOTIFY, >- attach_adapter: &tas_attach_adapter, >- detach_client: &tas_detach_client, >- command: NULL, >- inc_use: NULL, /* &tas_inc_use, */ >- dec_use: NULL /* &tas_dev_use */ >-}; > >-int >-tumbler_get_volume(uint * left_vol, uint *right_vol) >+static inline int >+register_width(enum tas3001c_reg_t r) > { >- struct tas_data_t *data; >+ switch(r) { >+ case TAS3001C_REG_MCR: >+ case TAS3001C_REG_TREBLE: >+ case TAS3001C_REG_BASS: >+ return 1; > >- if (!tumbler_client) >- return -1; >+ case TAS3001C_REG_DRC: >+ return 2; > >- data = (struct tas_data_t *) (tumbler_client->data); >- *left_vol = data->left_vol; >- *right_vol = data->right_vol; >- >- return 0; >+ case TAS3001C_REG_MIXER1: >+ case TAS3001C_REG_MIXER2: >+ return 3; >+ >+ case TAS3001C_REG_VOLUME: >+ return 6; >+ >+ case TAS3001C_REG_LEFT_BIQUAD0: >+ case TAS3001C_REG_LEFT_BIQUAD1: >+ case TAS3001C_REG_LEFT_BIQUAD2: >+ case TAS3001C_REG_LEFT_BIQUAD3: >+ case TAS3001C_REG_LEFT_BIQUAD4: >+ case TAS3001C_REG_LEFT_BIQUAD5: >+ case TAS3001C_REG_LEFT_BIQUAD6: >+ >+ case TAS3001C_REG_RIGHT_BIQUAD0: >+ case TAS3001C_REG_RIGHT_BIQUAD1: >+ case TAS3001C_REG_RIGHT_BIQUAD2: >+ case TAS3001C_REG_RIGHT_BIQUAD3: >+ case TAS3001C_REG_RIGHT_BIQUAD4: >+ case TAS3001C_REG_RIGHT_BIQUAD5: >+ case TAS3001C_REG_RIGHT_BIQUAD6: >+ return 15; >+ >+ default: >+ return 0; >+ } > } > >-int >-tumbler_set_register(uint reg, uint size, char *block) >-{ >- if (i2c_smbus_write_block_data(tumbler_client, reg, size, block) < 0) { >- printk("tas3001c: I2C write failed \n"); >- return -1; >+static int >+tas3001c_write_register( struct tas3001c_data_t *self, >+ enum tas3001c_reg_t reg_num, >+ char *data, >+ uint write_mode) >+{ >+ if (reg_num==TAS3001C_REG_MCR || >+ reg_num==TAS3001C_REG_BASS || >+ reg_num==TAS3001C_REG_TREBLE) { >+ return tas_write_byte_register(&self->super, >+ (uint)reg_num, >+ *data, >+ write_mode); >+ } else { >+ return tas_write_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num), >+ data, >+ write_mode); > } >- return 0; > } > >-int >-tumbler_get_pcm_lvl(uint *pcm_lvl) >+static int >+tas3001c_sync_register( struct tas3001c_data_t *self, >+ enum tas3001c_reg_t reg_num) > { >- struct tas_data_t *data; >- >- if (!tumbler_client) >- return -1; >+ if (reg_num==TAS3001C_REG_MCR || >+ reg_num==TAS3001C_REG_BASS || >+ reg_num==TAS3001C_REG_TREBLE) { >+ return tas_sync_byte_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num)); >+ } else { >+ return tas_sync_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num)); >+ } >+} > >- data = (struct tas_data_t *) (tumbler_client->data); >- *pcm_lvl = data->pcm_level; >+static int >+tas3001c_read_register( struct tas3001c_data_t *self, >+ enum tas3001c_reg_t reg_num, >+ char *data, >+ uint write_mode) >+{ >+ return tas_read_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num), >+ data); >+} >+ >+static inline int >+tas3001c_fast_load(struct tas3001c_data_t *self, int fast) >+{ >+ if (fast) >+ self->super.shadow[TAS3001C_REG_MCR][0] |= 0x80; >+ else >+ self->super.shadow[TAS3001C_REG_MCR][0] &= 0x7f; >+ return tas3001c_sync_register(self,TAS3001C_REG_MCR); >+} >+ >+static uint >+tas3001c_supported_mixers(struct tas3001c_data_t *self) >+{ >+ return SOUND_MASK_VOLUME | >+ SOUND_MASK_PCM | >+ SOUND_MASK_ALTPCM | >+ SOUND_MASK_TREBLE | >+ SOUND_MASK_BASS; >+} > >- return 0; >+static int >+tas3001c_mixer_is_stereo(struct tas3001c_data_t *self,int mixer) >+{ >+ switch(mixer) { >+ case SOUND_MIXER_VOLUME: >+ return 1; >+ default: >+ return 0; >+ } > } > >-int >-tumbler_get_treble(uint *treble) >+static uint >+tas3001c_stereo_mixers(struct tas3001c_data_t *self) > { >- struct tas_data_t *data; >+ uint r=tas3001c_supported_mixers(self); >+ uint i; >+ >+ for (i=1; i<SOUND_MIXER_NRDEVICES; i++) >+ if (r&(1<<i) && !tas3001c_mixer_is_stereo(self,i)) >+ r &= ~(1<<i); >+ return r; >+} > >- if (!tumbler_client) >+static int >+tas3001c_get_mixer_level(struct tas3001c_data_t *self,int mixer,uint *level) >+{ >+ if (!self) > return -1; >- >- data = (struct tas_data_t *) (tumbler_client->data); >- *treble = data->treble; >+ >+ *level=self->super.mixer[mixer]; > > return 0; > } > >-int >-tumbler_get_bass(uint *bass) >+static int >+tas3001c_set_mixer_level(struct tas3001c_data_t *self,int mixer,uint level) > { >- struct tas_data_t *data; >- >- if (!tumbler_client) >- return -1; >+ int rc; >+ tas_shadow_t *shadow; > >- data = (struct tas_data_t *) (tumbler_client->data); >- *bass = data->bass; >+ uint temp; >+ uint offset=0; > >+ if (!self) >+ return -1; >+ >+ shadow=self->super.shadow; >+ >+ if (!tas3001c_mixer_is_stereo(self,mixer)) >+ level = tas_mono_to_stereo(level); >+ >+ switch(mixer) { >+ case SOUND_MIXER_VOLUME: >+ temp = tas3001c_gain.master[level&0xff]; >+ shadow[TAS3001C_REG_VOLUME][0] = (temp >> 16) & 0xff; >+ shadow[TAS3001C_REG_VOLUME][1] = (temp >> 8) & 0xff; >+ shadow[TAS3001C_REG_VOLUME][2] = (temp >> 0) & 0xff; >+ temp = tas3001c_gain.master[(level>>8)&0xff]; >+ shadow[TAS3001C_REG_VOLUME][3] = (temp >> 16) & 0xff; >+ shadow[TAS3001C_REG_VOLUME][4] = (temp >> 8) & 0xff; >+ shadow[TAS3001C_REG_VOLUME][5] = (temp >> 0) & 0xff; >+ rc = tas3001c_sync_register(self,TAS3001C_REG_VOLUME); >+ break; >+ case SOUND_MIXER_ALTPCM: >+ /* tas3001c_fast_load(self, 1); */ >+ level = tas_mono_to_stereo(level); >+ temp = tas3001c_gain.mixer[level&0xff]; >+ shadow[TAS3001C_REG_MIXER2][offset+0] = (temp >> 16) & 0xff; >+ shadow[TAS3001C_REG_MIXER2][offset+1] = (temp >> 8) & 0xff; >+ shadow[TAS3001C_REG_MIXER2][offset+2] = (temp >> 0) & 0xff; >+ rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER2); >+ /* tas3001c_fast_load(self, 0); */ >+ break; >+ case SOUND_MIXER_PCM: >+ /* tas3001c_fast_load(self, 1); */ >+ level = tas_mono_to_stereo(level); >+ temp = tas3001c_gain.mixer[level&0xff]; >+ shadow[TAS3001C_REG_MIXER1][offset+0] = (temp >> 16) & 0xff; >+ shadow[TAS3001C_REG_MIXER1][offset+1] = (temp >> 8) & 0xff; >+ shadow[TAS3001C_REG_MIXER1][offset+2] = (temp >> 0) & 0xff; >+ rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER1); >+ /* tas3001c_fast_load(self, 0); */ >+ break; >+ case SOUND_MIXER_TREBLE: >+ temp = tas3001c_gain.treble[level&0xff]; >+ shadow[TAS3001C_REG_TREBLE][0]=temp&0xff; >+ rc = tas3001c_sync_register(self,TAS3001C_REG_TREBLE); >+ break; >+ case SOUND_MIXER_BASS: >+ temp = tas3001c_gain.bass[level&0xff]; >+ shadow[TAS3001C_REG_BASS][0]=temp&0xff; >+ rc = tas3001c_sync_register(self,TAS3001C_REG_BASS); >+ break; >+ default: >+ rc = -1; >+ break; >+ } >+ if (rc < 0) >+ return rc; >+ self->super.mixer[mixer]=level; > return 0; > } > >-int >-tumbler_set_bass(uint bass) >+static int >+tas3001c_leave_sleep(struct tas3001c_data_t *self) > { >- uint cur_bass_pers = bass; >- char block; >- struct tas_data_t *data; >+ unsigned char mcr = (1<<6)+(2<<4)+(2<<2); > >- if (!tumbler_client) >+ if (!self) > return -1; > >- data = (struct tas_data_t *) (tumbler_client->data); >+ /* Make sure something answers on the i2c bus */ >+ if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, >+ WRITE_NORMAL|FORCE_WRITE) < 0) >+ return -1; >+ >+ tas3001c_fast_load(self, 1); >+ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); >+ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); > >- bass &= 0xff; >- if (bass > TAS_SETTING_MAX) >- bass = TAS_SETTING_MAX; >- bass = ((bass * 72) / TAS_SETTING_MAX) << 0; >- bass = tas_bass_table[bass]; >- block = (bass >> 0) & 0xff; >+ tas3001c_fast_load(self, 0); > >- if (tumbler_set_register(TAS_SET_BASS, &block) < 0) { >- printk("tas3001c: failed to set bass \n"); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); >+ >+ return 0; >+} >+ >+static int >+tas3001c_enter_sleep(struct tas3001c_data_t *self) >+{ >+ /* Stub for now, but I have the details on low-power mode */ >+ if (!self) > return -1; >- } >- data->bass = cur_bass_pers; > return 0; > } > >-int >-tumbler_set_treble(uint treble) >+static int >+tas3001c_sync_biquad( struct tas3001c_data_t *self, >+ u_int channel, >+ u_int filter) > { >- uint cur_treble_pers = treble; >- char block; >- struct tas_data_t *data; >+ enum tas3001c_reg_t reg; > >- if (!tumbler_client) >- return -1; >+ if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || >+ filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; > >- data = (struct tas_data_t *) (tumbler_client->data); >+ reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; > >- treble &= 0xff; >- if (treble > TAS_SETTING_MAX) >- treble = TAS_SETTING_MAX; >- treble = ((treble * 72) / TAS_SETTING_MAX) << 0; >- treble = tas_treble_table[treble]; >- block = (treble >> 0) & 0xff; >+ return tas3001c_sync_register(self,reg); >+} >+ >+static int >+tas3001c_write_biquad_shadow( struct tas3001c_data_t *self, >+ u_int channel, >+ u_int filter, >+ const union tas_biquad_t *biquad) >+{ >+ tas_shadow_t *shadow=self->super.shadow; >+ enum tas3001c_reg_t reg; >+ >+ if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || >+ filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; >+ >+ reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; >+ >+ SET_4_20(shadow[reg], 0,biquad->coeff.b0); >+ SET_4_20(shadow[reg], 3,biquad->coeff.b1); >+ SET_4_20(shadow[reg], 6,biquad->coeff.b2); >+ SET_4_20(shadow[reg], 9,biquad->coeff.a1); >+ SET_4_20(shadow[reg],12,biquad->coeff.a2); > >- if (tumbler_set_register(TAS_SET_TREBLE, &block) < 0) { >- printk("tas3001c: failed to set treble \n"); >- return -1; >- } >- data->treble = cur_treble_pers; > return 0; > } > >-int >-tumbler_set_pcm_lvl(uint pcm_lvl) >+static int >+tas3001c_write_biquad( struct tas3001c_data_t *self, >+ u_int channel, >+ u_int filter, >+ const union tas_biquad_t *biquad) > { >- uint pcm_lvl_pers = pcm_lvl; >- unsigned char block[3]; >- struct tas_data_t *data; >+ int rc; > >- if (!tumbler_client) >- return -1; >+ rc=tas3001c_write_biquad_shadow(self, channel, filter, biquad); >+ if (rc < 0) return rc; > >- data = (struct tas_data_t *) (tumbler_client->data); >+ return tas3001c_sync_biquad(self, channel, filter); >+} > >- pcm_lvl &= 0xff; >- if (pcm_lvl > TAS_SETTING_MAX) >- pcm_lvl = TAS_SETTING_MAX; >- pcm_lvl = ((pcm_lvl * 176) / TAS_SETTING_MAX) << 0; >+static int >+tas3001c_write_biquad_list( struct tas3001c_data_t *self, >+ u_int filter_count, >+ u_int flags, >+ struct tas_biquad_ctrl_t *biquads) >+{ >+ int i; >+ int rc; > >- pcm_lvl = tas_input_table[pcm_lvl]; >+ if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); > >- block[0] = (pcm_lvl >> 16) & 0xff; >- block[1] = (pcm_lvl >> 8) & 0xff; >- block[2] = (pcm_lvl >> 0) & 0xff; >+ for (i=0; i<filter_count; i++) { >+ rc=tas3001c_write_biquad(self, >+ biquads[i].channel, >+ biquads[i].filter, >+ &biquads[i].data); >+ if (rc < 0) break; >+ } > >- if (tumbler_set_register(TAS_SET_MIXER1, block) < 0) { >- printk("tas3001c: failed to set input level \n"); >- return -1; >+ if (flags & TAS_BIQUAD_FAST_LOAD) { >+ tas3001c_fast_load(self,0); >+ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); > } >- data->pcm_level = pcm_lvl_pers; > >- return 0; >+ return rc; > } > >-int >-tumbler_set_volume(uint left_vol, uint right_vol) >+static int >+tas3001c_read_biquad( struct tas3001c_data_t *self, >+ u_int channel, >+ u_int filter, >+ union tas_biquad_t *biquad) >+{ >+ tas_shadow_t *shadow=self->super.shadow; >+ enum tas3001c_reg_t reg; >+ >+ if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || >+ filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; >+ >+ reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; >+ >+ biquad->coeff.b0=GET_4_20(shadow[reg], 0); >+ biquad->coeff.b1=GET_4_20(shadow[reg], 3); >+ biquad->coeff.b2=GET_4_20(shadow[reg], 6); >+ biquad->coeff.a1=GET_4_20(shadow[reg], 9); >+ biquad->coeff.a2=GET_4_20(shadow[reg],12); >+ >+ return 0; >+} >+ >+static int >+tas3001c_eq_rw( struct tas3001c_data_t *self, >+ u_int cmd, >+ u_long arg) > { >- uint left_vol_pers = left_vol; >- uint right_vol_pers = right_vol; >- unsigned char block[6]; >- struct tas_data_t *data; >+ int rc; >+ struct tas_biquad_ctrl_t biquad; > >- if (!tumbler_client) >- return -1; >+ if (copy_from_user((void *)&biquad, (const void *)arg, sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } > >- data = (struct tas_data_t *) (tumbler_client->data); >+ if (cmd & SIOC_IN) { >+ rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ } > >- left_vol &= 0xff; >- if (left_vol > TAS_SETTING_MAX) >- left_vol = TAS_SETTING_MAX; >+ if (cmd & SIOC_OUT) { >+ rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ >+ if (copy_to_user((void *)arg, (const void *)&biquad, sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } > >- right_vol = (right_vol >> 8) & 0xff; >- if (right_vol > TAS_SETTING_MAX) >- right_vol = TAS_SETTING_MAX; >+ } >+ return 0; >+} > >- left_vol = ((left_vol * 176) / TAS_SETTING_MAX) << 0; >- right_vol = ((right_vol * 176) / TAS_SETTING_MAX) << 0; >+static int >+tas3001c_eq_list_rw( struct tas3001c_data_t *self, >+ u_int cmd, >+ u_long arg) >+{ >+ int rc; >+ int filter_count; >+ int flags; >+ int i,j; >+ char sync_required[2][6]; >+ struct tas_biquad_ctrl_t biquad; >+ >+ memset(sync_required,0,sizeof(sync_required)); >+ >+ if (copy_from_user((void *)&filter_count, >+ (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,filter_count), >+ sizeof(int))) { >+ return -EFAULT; >+ } > >- left_vol = tas_volume_table[left_vol]; >- right_vol = tas_volume_table[right_vol]; >+ if (copy_from_user((void *)&flags, >+ (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,flags), >+ sizeof(int))) { >+ return -EFAULT; >+ } > >- block[0] = (left_vol >> 16) & 0xff; >- block[1] = (left_vol >> 8) & 0xff; >- block[2] = (left_vol >> 0) & 0xff; >+ if (cmd & SIOC_IN) { >+ } > >- block[3] = (right_vol >> 16) & 0xff; >- block[4] = (right_vol >> 8) & 0xff; >- block[5] = (right_vol >> 0) & 0xff; >+ for (i=0; i < filter_count; i++) { >+ if (copy_from_user((void *)&biquad, >+ (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), >+ sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+ if (cmd & SIOC_IN) { >+ sync_required[biquad.channel][biquad.filter]=1; >+ rc=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ } >+ >+ if (cmd & SIOC_OUT) { >+ rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ >+ if (copy_to_user((void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), >+ (const void *)&biquad, >+ sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } >+ } >+ } > >- if (tumbler_set_register(TAS_SET_VOLUME, block) < 0) { >- printk("tas3001c: failed to set volume \n"); >- return -1; >+ if (cmd & SIOC_IN) { >+ if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); >+ for (i=0; i<2; i++) { >+ for (j=0; j<6; j++) { >+ if (sync_required[i][j]) { >+ rc=tas3001c_sync_biquad(self, i, j); >+ if (rc < 0) return rc; >+ } >+ } >+ } >+ if (flags & TAS_BIQUAD_FAST_LOAD) { >+ tas3001c_fast_load(self,0); >+ /* now we need to set up the mixers again, >+ because leaving fast mode resets them. */ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); >+ } > } >- data->left_vol = left_vol_pers; >- data->right_vol = right_vol_pers; > > return 0; > } > >-int >-tumbler_leave_sleep(void) >-{ >- /* Stub for now, but I have the details on low-power mode */ >- if (!tumbler_client) >- return -1; >+static int >+tas3001c_update_drce( struct tas3001c_data_t *self, >+ int flags, >+ struct tas_drce_t *drce) >+{ >+ tas_shadow_t *shadow; >+ shadow=self->super.shadow; >+ >+ shadow[TAS3001C_REG_DRC][1] = 0xc1; >+ >+ if (flags & TAS_DRCE_THRESHOLD) { >+ self->drce_state.threshold=quantize_db(drce->threshold); >+ shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold); >+ } > >- return 0; >+ if (flags & TAS_DRCE_ENABLE) { >+ self->drce_state.enable = drce->enable; >+ } >+ >+ if (!self->drce_state.enable) { >+ shadow[TAS3001C_REG_DRC][0] = 0xf0; >+ } >+ >+#ifdef DEBUG_DRCE >+ printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n", >+ self->drce_state.enable, >+ self->drce_state.threshold); >+ >+ printk("DRCE IOCTL: reg [ %02x %02x ]\n", >+ (unsigned char)shadow[TAS3001C_REG_DRC][0], >+ (unsigned char)shadow[TAS3001C_REG_DRC][1]); >+#endif >+ >+ return tas3001c_sync_register(self, TAS3001C_REG_DRC); > } > >-int >-tumbler_enter_sleep(void) >+static int >+tas3001c_drce_rw( struct tas3001c_data_t *self, >+ u_int cmd, >+ u_long arg) > { >- /* Stub for now, but I have the details on low-power mode */ >- if (!tumbler_client) >- return -1; >+ int rc; >+ struct tas_drce_ctrl_t drce_ctrl; >+ >+ if (copy_from_user((void *)&drce_ctrl, >+ (const void *)arg, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+#ifdef DEBUG_DRCE >+ printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n", >+ drce_ctrl.flags, >+ drce_ctrl.data.enable, >+ drce_ctrl.data.threshold); >+#endif >+ >+ if (cmd & SIOC_IN) { >+ rc = tas3001c_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); >+ if (rc < 0) >+ return rc; >+ } >+ >+ if (cmd & SIOC_OUT) { >+ if (drce_ctrl.flags & TAS_DRCE_ENABLE) >+ drce_ctrl.data.enable = self->drce_state.enable; >+ >+ if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) >+ drce_ctrl.data.threshold = self->drce_state.threshold; >+ >+ if (copy_to_user((void *)arg, >+ (const void *)&drce_ctrl, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ } > > return 0; > } > >-static int >-tas_attach_adapter(struct i2c_adapter *adapter) >+static void >+tas3001c_update_device_parameters(struct tas3001c_data_t *self) > { >- if (!strncmp(adapter->name, "mac-io", 6)) >- tas_detect_client(adapter, tas_i2c_address); >+ int i,j; > >- return 0; >+ if (!self) return; >+ >+ if (self->output_id == TAS_OUTPUT_HEADPHONES) { >+ tas3001c_fast_load(self, 1); >+ >+ for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) { >+ for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) { >+ tas3001c_write_biquad(self, i, j, &tas3001c_eq_unity); >+ } >+ } >+ >+ tas3001c_fast_load(self, 0); >+ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); >+ >+ return; >+ } >+ >+ for (i=0; tas3001c_eq_prefs[i]; i++) { >+ struct tas_eq_pref_t *eq = tas3001c_eq_prefs[i]; >+ >+ if (eq->device_id == self->device_id && >+ (eq->output_id == 0 || eq->output_id == self->output_id) && >+ (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { >+ >+ tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce); >+ tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); >+ >+ break; >+ } >+ } > } > >-static int >-tas_init_client(struct i2c_client * new_client) >+static void >+tas3001c_device_change_handler(void *self) > { >- /* Make sure something answers on the i2c bus >- */ >+ if (!self) return; > >- if (i2c_smbus_write_byte_data(new_client, 1, (1<<6)+(2<<4)+(2<<2)+0) < 0) >- return -1; >+ tas3001c_update_device_parameters((struct tas3001c_data_t *)self); >+} >+ >+static struct tq_struct device_change_task; > >- tumbler_client = new_client; >+static int >+tas3001c_output_device_change( struct tas3001c_data_t *self, >+ int device_id, >+ int output_id, >+ int speaker_id) >+{ >+ self->device_id=device_id; >+ self->output_id=output_id; >+ self->speaker_id=speaker_id; > >- tumbler_set_volume(VOL_DEFAULT, VOL_DEFAULT); >- tumbler_set_pcm_lvl(INPUT_DEFAULT); >- tumbler_set_bass(BASS_DEFAULT); >- tumbler_set_treble(TREBLE_DEFAULT); >+ schedule_task(&device_change_task); > > return 0; > } > > static int >-tas_detect_client(struct i2c_adapter *adapter, int address) >-{ >- int rc = 0; >- struct i2c_client *new_client; >- struct tas_data_t *data; >- const char *client_name = "tas 3001c Digital Equalizer"; >- >- new_client = kmalloc( >- sizeof(struct i2c_client) + sizeof(struct tas_data_t), >- GFP_KERNEL); >- if (!new_client) { >- rc = -ENOMEM; >- goto bail; >- } >+tas3001c_device_ioctl( struct tas3001c_data_t *self, >+ u_int cmd, >+ u_long arg) >+{ >+ switch (cmd) { >+ case TAS_READ_EQ: >+ case TAS_WRITE_EQ: >+ return tas3001c_eq_rw(self, cmd, arg); >+ >+ case TAS_READ_EQ_LIST: >+ case TAS_WRITE_EQ_LIST: >+ return tas3001c_eq_list_rw(self, cmd, arg); > >- /* This is tricky, but it will set the data to the right value. */ >- new_client->data = new_client + 1; >- data = (struct tas_data_t *) (new_client->data); >+ case TAS_READ_EQ_FILTER_COUNT: >+ put_user(TAS3001C_BIQUAD_FILTER_COUNT, (uint *)(arg)); >+ return 0; > >- new_client->addr = address; >- new_client->data = data; >- new_client->adapter = adapter; >- new_client->driver = &tas_driver; >- new_client->flags = 0; >+ case TAS_READ_EQ_CHANNEL_COUNT: >+ put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, (uint *)(arg)); >+ return 0; > >- strcpy(new_client->name,client_name); >+ case TAS_READ_DRCE: >+ case TAS_WRITE_DRCE: >+ return tas3001c_drce_rw(self, cmd, arg); > >- new_client->id = tas_id++; /* Automatically unique */ >+ case TAS_READ_DRCE_CAPS: >+ put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, (uint *)(arg)); >+ return 0; > >- if (tas_init_client(new_client)) { >- rc = -ENODEV; >- goto bail; >+ case TAS_READ_DRCE_MIN: >+ case TAS_READ_DRCE_MAX: { >+ struct tas_drce_ctrl_t drce_ctrl; >+ >+ if (copy_from_user((void *)&drce_ctrl, >+ (const void *)arg, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+ if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { >+ if (cmd == TAS_READ_DRCE_MIN) { >+ drce_ctrl.data.threshold=-36<<8; >+ } else { >+ drce_ctrl.data.threshold=-6<<8; >+ } >+ } >+ >+ if (copy_to_user((void *)arg, >+ (const void *)&drce_ctrl, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } > } >- >- /* Tell the i2c layer a new client has arrived */ >- if (i2c_attach_client(new_client)) { >- rc = -ENODEV; >- goto bail; > } >-bail: >- if (rc && new_client) >- kfree(new_client); >- return rc; >+ >+ return -EINVAL; > } > > static int >-tas_detach_client(struct i2c_client *client) >+tas3001c_init_mixer(struct tas3001c_data_t *self) > { >- if (client == tumbler_client) >- tumbler_client = NULL; >+ unsigned char mcr = (1<<6)+(2<<4)+(2<<2); >+ >+ /* Make sure something answers on the i2c bus */ >+ if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, >+ WRITE_NORMAL|FORCE_WRITE) < 0) >+ return -1; >+ >+ tas3001c_fast_load(self, 1); >+ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6); >+ >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); >+ (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6); >+ >+ tas3001c_fast_load(self, 0); >+ >+ tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); > >- i2c_detach_client(client); >- kfree(client); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); > > return 0; > } > >-int >-tas_cleanup(void) >+static int >+tas3001c_uninit_mixer(struct tas3001c_data_t *self) > { >- if (!tas_initialized) >- return -ENODEV; >- i2c_del_driver(&tas_driver); >- tas_initialized = 0; >+ tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, 0); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); >+ >+ tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, 0); >+ tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); > > return 0; > } > >-int >-tas_init(void) >+static int >+tas3001c_init(struct i2c_client *client) > { >- int rc; >- u32* paddr; >- >- if (tas_initialized) >- return 0; >+ struct tas3001c_data_t *self; >+ int i,j; > >- tas_node = find_devices("deq"); >- if (tas_node == NULL) >- return -ENODEV; >- >- printk(KERN_INFO "tas3001c driver version %s (%s)\n",TAS_VERSION,TAS_DATE); >- paddr = (u32 *)get_property(tas_node, "i2c-address", NULL); >- if (paddr) { >- tas_i2c_address = (*paddr) >> 1; >- printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", >- tas_i2c_address); >- } else >- printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address); >- >- if ((rc = i2c_add_driver(&tas_driver))) { >- printk("tas3001c: Driver registration failed, module not inserted.\n"); >- tas_cleanup(); >- return rc; >+ self = kmalloc(sizeof(struct tas3001c_data_t) + >+ TAS3001C_REG_MAX * sizeof(tas_shadow_t), >+ GFP_KERNEL); >+ if (self == NULL) >+ return -ENOMEM; >+ client->data = (void *)self; >+ self->super.client = client; >+ self->super.shadow = (tas_shadow_t *)(self+1); >+ >+ self->output_id=TAS_OUTPUT_HEADPHONES; >+ self->device_id=0; >+ self->speaker_id=0; >+ >+ for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) { >+ for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) { >+ tas3001c_write_biquad_shadow(self, i, j, &tas3001c_eq_unity); >+ } > } >- tas_initialized = 1; >+ INIT_TQUEUE(&device_change_task, tas3001c_device_change_handler, (void *)self); >+ > return 0; > } >+ >+static void >+tas3001c_uninit(struct tas3001c_data_t *self) >+{ >+ tas3001c_uninit_mixer(self); >+ kfree(self); >+} >+ >+struct tas_driver_hooks_t tas3001c_hooks = { >+ init: (tas_hook_init_t)tas3001c_init, >+ post_init: (tas_hook_post_init_t)tas3001c_init_mixer, >+ uninit: (tas_hook_uninit_t)tas3001c_uninit, >+ >+ get_mixer_level: (tas_hook_get_mixer_level_t)tas3001c_get_mixer_level, >+ set_mixer_level: (tas_hook_set_mixer_level_t)tas3001c_set_mixer_level, >+ >+ enter_sleep: (tas_hook_enter_sleep_t)tas3001c_enter_sleep, >+ leave_sleep: (tas_hook_leave_sleep_t)tas3001c_leave_sleep, >+ >+ supported_mixers: (tas_hook_supported_mixers_t)tas3001c_supported_mixers, >+ mixer_is_stereo: (tas_hook_mixer_is_stereo_t)tas3001c_mixer_is_stereo, >+ stereo_mixers: (tas_hook_stereo_mixers_t)tas3001c_stereo_mixers, >+ >+ output_device_change: (tas_hook_output_device_change_t)tas3001c_output_device_change, >+ >+ device_ioctl: (tas_hook_device_ioctl_t)tas3001c_device_ioctl >+}; >+ >+/* >+ * Local Variables: >+ * tab-width: 8 >+ * indent-tabs-mode: t >+ * c-basic-offset: 8 >+ * End: >+ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3001c.h linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3001c.h >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3001c.h 2002-02-25 20:38:05.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3001c.h 2003-08-25 23:37:52.000000000 +0200 >@@ -1,5 +1,5 @@ > /* >- * Header file for the i2c/i2s based TA3001C sound chip used >+ * Header file for the i2c/i2s based TA3001c sound chip used > * on some Apple hardware. Also known as "tumbler". > * > * This file is subject to the terms and conditions of the GNU General Public >@@ -9,240 +9,56 @@ > * Written by Christopher C. Chimelis <chris@debian.org> > */ > >-#ifndef _tas3001c_h_ >-#define _tas3001c_h_ >+#ifndef _TAS3001C_H_ >+#define _TAS3001C_H_ > >-/* >- * Macros that correspond to the registers that we write to >- * when setting the various values. >- */ >-#define TAS_DRC 0x02 /* DRC */ >-#define TAS_VOLUME 0x04 /* Volume */ >-#define TAS_TREBLE 0x05 /* Treble */ >-#define TAS_BASS 0x06 /* Bass */ >-#define TAS_MIXER1 0x07 /* PCM line */ >-#define TAS_MIXER2 0x08 /* Input (Unk) */ >- >-/* >- * Macros that define various arguments to tas_set_register() >- */ >-#define TAS_SET_DRC TAS_DRC, 2 >-#define TAS_SET_VOLUME TAS_VOLUME, 6 >-#define TAS_SET_TREBLE TAS_TREBLE, 1 >-#define TAS_SET_BASS TAS_BASS, 1 >-#define TAS_SET_MIXER1 TAS_MIXER1, 3 >-#define TAS_SET_MIXER2 TAS_MIXER2, 3 >+#include <linux/types.h> > >+#include "tas_common.h" >+#include "tas_eq_prefs.h" > > /* >- * tas_volume_table contains lookup values for the volume settings >- * for tumbler. This is straight from the programming manual >- * for the chip, however, it's zero-sourced for your shopping pleasure >- * (meaning, you'll have to compute the difference between the desired >- * dB and the index value of the proper setting. >- * >- * This table should've been replaced by the formula: >- * dB = 20 log(x) >- * but, since there's no log() or supporting functions like exp(), >- * my implementation of the above won't work. Yeah, I could do it >- * the hard way, but this table is just easier :-) >- * >- * For reference, -70 dB = tas_volume_table[0] >+ * Macros that correspond to the registers that we write to >+ * when setting the various values. > */ > >-static unsigned int tas_volume_table[] = { >- 0x00000015, 0x00000016, 0x00000017, /* -70.0, -69.5, -69.0 */ >- 0x00000019, 0x0000001a, 0x0000001c, /* -68.5, -68.0, -67.5 */ >- 0x0000001d, 0x0000001f, 0x00000021, /* -67.0, -66.5, -66.0 */ >- 0x00000023, 0x00000025, 0x00000027, /* -65.5, -65.0, -64.5 */ >- 0x00000029, 0x0000002c, 0x0000002e, /* -64.0, -63.5, -63.0 */ >- 0x00000031, 0x00000034, 0x00000037, /* -62.5, -62.0, -61.5 */ >- 0x0000003a, 0x0000003e, 0x00000042, /* -61.0, -60.5, -60.0 */ >- 0x00000045, 0x0000004a, 0x0000004e, /* -59.5, -59.0, -58.5 */ >- 0x00000053, 0x00000057, 0x0000005d, /* -58.0, -57.5, -57.0 */ >- 0x00000062, 0x00000068, 0x0000006e, /* -56.5, -56.0, -55.5 */ >- 0x00000075, 0x0000007b, 0x00000083, /* -55.0, -54.5, -54.0 */ >- 0x0000008b, 0x00000093, 0x0000009b, /* -53.5, -53.0, -52.5 */ >- 0x000000a5, 0x000000ae, 0x000000b9, /* -52.0, -51.5, -51.0 */ >- 0x000000c4, 0x000000cf, 0x000000dc, /* -50.5, -50.0, -49.5 */ >- 0x000000e9, 0x000000f6, 0x00000105, /* -49.0, -48.5, -48.0 */ >- 0x00000114, 0x00000125, 0x00000136, /* -47.5, -47.0, -46.5 */ >- 0x00000148, 0x0000015c, 0x00000171, /* -46.0, -45.5, -45.0 */ >- 0x00000186, 0x0000019e, 0x000001b6, /* -44.5, -44.0, -43.5 */ >- 0x000001d0, 0x000001eb, 0x00000209, /* -43.0, -42.5, -42.0 */ >- 0x00000227, 0x00000248, 0x0000026b, /* -41.5, -41.0, -40.5 */ >- 0x0000028f, 0x000002b6, 0x000002df, /* -40.0, -39.5, -39.0 */ >- 0x0000030b, 0x00000339, 0x0000036a, /* -38.5, -38.0, -37.5 */ >- 0x0000039e, 0x000003d5, 0x0000040f, /* -37.0, -36.5, -36.0 */ >- 0x0000044c, 0x0000048d, 0x000004d2, /* -35.5, -35.0, -34.5 */ >- 0x0000051c, 0x00000569, 0x000005bb, /* -34.0, -33.5, -33.0 */ >- 0x00000612, 0x0000066e, 0x000006d0, /* -32.5, -32.0, -31.5 */ >- 0x00000737, 0x000007a5, 0x00000818, /* -31.0, -30.5, -30.0 */ >- 0x00000893, 0x00000915, 0x0000099f, /* -29.5, -29.0, -28.5 */ >- 0x00000a31, 0x00000acc, 0x00000b6f, /* -28.0, -27.5, -27.0 */ >- 0x00000c1d, 0x00000cd5, 0x00000d97, /* -26.5, -26.0, -25.5 */ >- 0x00000e65, 0x00000f40, 0x00001027, /* -25.0, -24.5, -24.0 */ >- 0x0000111c, 0x00001220, 0x00001333, /* -23.5, -23.0, -22.5 */ >- 0x00001456, 0x0000158a, 0x000016d1, /* -22.0, -21.5, -21.0 */ >- 0x0000182b, 0x0000199a, 0x00001b1e, /* -20.5, -20.0, -19.5 */ >- 0x00001cb9, 0x00001e6d, 0x0000203a, /* -19.0, -18.5, -18.0 */ >- 0x00002223, 0x00002429, 0x0000264e, /* -17.5, -17.0, -16.5 */ >- 0x00002893, 0x00002afa, 0x00002d86, /* -16.0, -15.5, -15.0 */ >- 0x00003039, 0x00003314, 0x0000361b, /* -14.5, -14.0, -13.5 */ >- 0x00003950, 0x00003cb5, 0x0000404e, /* -13.0, -12.5, -12.0 */ >- 0x0000441d, 0x00004827, 0x00004c6d, /* -11.5, -11.0, -10.5 */ >- 0x000050f4, 0x000055c0, 0x00005ad5, /* -10.0, -09.5, -09.0 */ >- 0x00006037, 0x000065ea, 0x00006bf4, /* -08.5, -08.0, -07.5 */ >- 0x0000725a, 0x00007920, 0x0000804e, /* -07.0, -06.5, -06.0 */ >- 0x000087e8, 0x00008ff6, 0x0000987d, /* -05.5, -05.0, -04.5 */ >- 0x0000a186, 0x0000ab19, 0x0000b53c, /* -04.0, -03.5, -03.0 */ >- 0x0000bff9, 0x0000cb59, 0x0000d766, /* -02.5, -02.0, -01.5 */ >- 0x0000e429, 0x0000f1ae, 0x00010000, /* -01.0, -00.5, 00.0 */ >- 0x00010f2b, 0x00011f3d, 0x00013042, /* +00.5, +01.0, +01.5 */ >- 0x00014249, 0x00015562, 0x0001699c, /* +02.0, +02.5, +03.0 */ >- 0x00017f09, 0x000195bc, 0x0001adc6, /* +03.5, +04.0, +04.5 */ >- 0x0001c73d, 0x0001e237, 0x0001feca, /* +05.0, +05.5, +06.0 */ >- 0x00021d0e, 0x00023d1d, 0x00025f12, /* +06.5, +07.0, +07.5 */ >- 0x0002830b, 0x0002a925, 0x0002d182, /* +08.0, +08.5, +09.0 */ >- 0x0002fc42, 0x0003298b, 0x00035983, /* +09.5, +10.0, +10.5 */ >- 0x00038c53, 0x0003c225, 0x0003fb28, /* +11.0, +11.5, +12.0 */ >- 0x0004378b, 0x00047783, 0x0004bb44, /* +12.5, +13.0, +13.5 */ >- 0x0005030a, 0x00054f10, 0x00059f98, /* +14.0, +14.5, +15.0 */ >- 0x0005f4e5, 0x00064f40, 0x0006aef6, /* +15.5, +16.0, +16.5 */ >- 0x00071457, 0x00077fbb, 0x0007f17b /* +17.0, +17.5, +18.0 */ >-}; >+#define TAS3001C_VERSION "0.3" >+#define TAS3001C_DATE "20011214" > >-/* tas_treble_table[] is a lookup table that holds the values to drop into >- * the treble setting register on the TAS. Again, there is a formula for >- * this one, but we use this instead due to lack of real math functions >- * in the kernel. >- */ >-static char tas_treble_table[] = { >- 0x96, 0x95, 0x94, /* -18.0, -17.5, -17.0 */ >- 0x93, 0x92, 0x91, /* -16.5, -16.0, -15.5 */ >- 0x90, 0x8f, 0x8e, /* -15.0, -14.5, -14.0 */ >- 0x8d, 0x8c, 0x8b, /* -13.5, -13.0, -12.5 */ >- 0x8a, 0x89, 0x88, /* -12.0, -11.5, -11.0 */ >- 0x87, 0x86, 0x85, /* -10.5, -10.0, -09.5 */ >- 0x84, 0x83, 0x82, /* -09.0, -08.5, -08.0 */ >- 0x81, 0x80, 0x7f, /* -07.5, -07.0, -06.5 */ >- 0x7e, 0x7d, 0x7c, /* -06.0, -05.5, -05.0 */ >- 0x7b, 0x7a, 0x79, /* -04.5, -04.0, -03.5 */ >- 0x78, 0x77, 0x76, /* -03.0, -02.5, -02.0 */ >- 0x75, 0x74, 0x73, /* -01.5, -01.0, -00.5 */ >- 0x72, 0x71, 0x70, /* 00.0, +00.5, +01.0 */ >- 0x6e, 0x6d, 0x6c, /* +01.5, +02.0, +02.5 */ >- 0x6b, 0x69, 0x68, /* +03.0, +03.5, +04.0 */ >- 0x66, 0x65, 0x63, /* +04.5, +05.0, +05.5 */ >- 0x62, 0x60, 0x5e, /* +06.0, +06.5, +07.0 */ >- 0x5c, 0x5a, 0x57, /* +07.5, +08.0, +08.5 */ >- 0x55, 0x52, 0x4f, /* +09.0, +09.5, +10.0 */ >- 0x4c, 0x49, 0x45, /* +10.5, +11.0, +11.5 */ >- 0x42, 0x3e, 0x3a, /* +12.0, +12.5, +13.0 */ >- 0x36, 0x32, 0x2d, /* +13.5, +14.0, +14.5 */ >- 0x28, 0x22, 0x1c, /* +15.0, +15.5, +16.0 */ >- 0x16, 0x10, 0x09, /* +16.5, +17.0, +17.5 */ >- 0x01 /* +18.0 */ >-}; >+#define I2C_DRIVERNAME_TAS3001C "TAS3001c driver V " TAS3001C_VERSION >+#define I2C_DRIVERID_TAS3001C (I2C_DRIVERID_TAS_BASE+0) > >-/* tas_bass_table[] is a lookup table that holds the values to drop into >- * the bass setting register on the TAS. Again, there is a formula for >- * this one, but we use this instead due to lack of real math functions >- * in the kernel. >- */ >-static char tas_bass_table[] = { >- 0x86, 0x82, 0x7f, /* -18.0, -17.5, -17.0 */ >- 0x7d, 0x7a, 0x78, /* -16.5, -16.0, -15.5 */ >- 0x76, 0x74, 0x72, /* -15.0, -14.5, -14.0 */ >- 0x70, 0x6e, 0x6d, /* -13.5, -13.0, -12.5 */ >- 0x6b, 0x69, 0x66, /* -12.0, -11.5, -11.0 */ >- 0x64, 0x61, 0x5f, /* -10.5, -10.0, -09.5 */ >- 0x5d, 0x5c, 0x5a, /* -09.0, -08.5, -08.0 */ >- 0x59, 0x58, 0x56, /* -07.5, -07.0, -06.5 */ >- 0x55, 0x54, 0x53, /* -06.0, -05.5, -05.0 */ >- 0x51, 0x4f, 0x4d, /* -04.5, -04.0, -03.5 */ >- 0x4b, 0x49, 0x46, /* -03.0, -02.5, -02.0 */ >- 0x44, 0x42, 0x40, /* -01.5, -01.0, -00.5 */ >- 0x3e, 0x3c, 0x3b, /* 00.0, +00.5, +01.0 */ >- 0x39, 0x38, 0x36, /* +01.5, +02.0, +02.5 */ >- 0x35, 0x33, 0x31, /* +03.0, +03.5, +04.0 */ >- 0x30, 0x2e, 0x2c, /* +04.5, +05.0, +05.5 */ >- 0x2b, 0x29, 0x28, /* +06.0, +06.5, +07.0 */ >- 0x26, 0x25, 0x23, /* +07.5, +08.0, +08.5 */ >- 0x21, 0x1f, 0x1c, /* +09.0, +09.5, +10.0 */ >- 0x19, 0x18, 0x17, /* +10.5, +11.0, +11.5 */ >- 0x16, 0x14, 0x13, /* +12.0, +12.5, +13.0 */ >- 0x12, 0x10, 0x0f, /* +13.5, +14.0, +14.5 */ >- 0x0d, 0x0b, 0x0a, /* +15.0, +15.5, +16.0 */ >- 0x08, 0x06, 0x03, /* +16.5, +17.0, +17.5 */ >- 0x01 /* +18.0 */ >-}; >+extern struct tas_driver_hooks_t tas3001c_hooks; >+extern struct tas_gain_t tas3001c_gain; >+extern struct tas_eq_pref_t *tas3001c_eq_prefs[]; >+ >+enum tas3001c_reg_t { >+ TAS3001C_REG_MCR = 0x01, >+ TAS3001C_REG_DRC = 0x02, >+ >+ TAS3001C_REG_VOLUME = 0x04, >+ TAS3001C_REG_TREBLE = 0x05, >+ TAS3001C_REG_BASS = 0x06, >+ TAS3001C_REG_MIXER1 = 0x07, >+ TAS3001C_REG_MIXER2 = 0x08, >+ >+ TAS3001C_REG_LEFT_BIQUAD0 = 0x0a, >+ TAS3001C_REG_LEFT_BIQUAD1 = 0x0b, >+ TAS3001C_REG_LEFT_BIQUAD2 = 0x0c, >+ TAS3001C_REG_LEFT_BIQUAD3 = 0x0d, >+ TAS3001C_REG_LEFT_BIQUAD4 = 0x0e, >+ TAS3001C_REG_LEFT_BIQUAD5 = 0x0f, >+ TAS3001C_REG_LEFT_BIQUAD6 = 0x10, >+ >+ TAS3001C_REG_RIGHT_BIQUAD0 = 0x13, >+ TAS3001C_REG_RIGHT_BIQUAD1 = 0x14, >+ TAS3001C_REG_RIGHT_BIQUAD2 = 0x15, >+ TAS3001C_REG_RIGHT_BIQUAD3 = 0x16, >+ TAS3001C_REG_RIGHT_BIQUAD4 = 0x17, >+ TAS3001C_REG_RIGHT_BIQUAD5 = 0x18, >+ TAS3001C_REG_RIGHT_BIQUAD6 = 0x19, > >-/* tas_input_table[] is a lookup table that holds the values to drop into >- * the setting registers on the TAS for "mixers 1 & 2" (which are the input >- * lines). Again, there is a formula for these, but we use this instead >- * due to lack of real math functions in the kernel. >- */ >-static unsigned int tas_input_table[] = { >- 0x00014b, 0x00015f, 0x000174, /* -70.0, -69.5, -69.0 */ >- 0x00018a, 0x0001a1, 0x0001ba, /* -68.5, -68.0, -67.5 */ >- 0x0001d4, 0x0001f0, 0x00020d, /* -67.0, -66.5, -66.0 */ >- 0x00022c, 0x00024d, 0x000270, /* -65.5, -65.0, -64.5 */ >- 0x000295, 0x0002bc, 0x0002e6, /* -64.0, -63.5, -63.0 */ >- 0x000312, 0x000340, 0x000372, /* -62.5, -62.0, -61.5 */ >- 0x0003a6, 0x0003dd, 0x000418, /* -61.0, -60.5, -60.0 */ >- 0x000456, 0x000498, 0x0004de, /* -59.5, -59.0, -58.5 */ >- 0x000528, 0x000576, 0x0005c9, /* -58.0, -57.5, -57.0 */ >- 0x000620, 0x00067d, 0x0006e0, /* -56.5, -56.0, -55.5 */ >- 0x000748, 0x0007b7, 0x00082c, /* -55.0, -54.5, -54.0 */ >- 0x0008a8, 0x00092b, 0x0009b6, /* -53.5, -53.0, -52.5 */ >- 0x000a49, 0x000ae5, 0x000b8b, /* -52.0, -51.5, -51.0 */ >- 0x000c3a, 0x000cf3, 0x000db8, /* -50.5, -50.0, -49.5 */ >- 0x000e88, 0x000f64, 0x00104e, /* -49.0, -48.5, -48.0 */ >- 0x001145, 0x00124b, 0x001361, /* -47.5, -47.0, -46.5 */ >- 0x001487, 0x0015be, 0x001708, /* -46.0, -45.5, -45.0 */ >- 0x001865, 0x0019d8, 0x001b60, /* -44.5, -44.0, -43.5 */ >- 0x001cff, 0x001eb7, 0x002089, /* -43.0, -42.5, -42.0 */ >- 0x002276, 0x002481, 0x0026ab, /* -41.5, -41.0, -40.5 */ >- 0x0028f5, 0x002b63, 0x002df5, /* -40.0, -39.5, -39.0 */ >- 0x0030ae, 0x003390, 0x00369e, /* -38.5, -38.0, -37.5 */ >- 0x0039db, 0x003d49, 0x0040ea, /* -37.0, -36.5, -36.0 */ >- 0x0044c3, 0x0048d6, 0x004d27, /* -35.5, -35.0, -34.5 */ >- 0x0051b9, 0x005691, 0x005bb2, /* -34.0, -33.5, -33.0 */ >- 0x006121, 0x0066e3, 0x006cfb, /* -32.5, -32.0, -31.5 */ >- 0x007370, 0x007a48, 0x008186, /* -31.0, -30.5, -30.0 */ >- 0x008933, 0x009154, 0x0099f1, /* -29.5, -29.0, -28.5 */ >- 0x00a310, 0x00acba, 0x00b6f6, /* -28.0, -27.5, -27.0 */ >- 0x00c1cd, 0x00cd49, 0x00d973, /* -26.5, -26.0, -25.5 */ >- 0x00e655, 0x00f3fb, 0x010270, /* -25.0, -24.5, -24.0 */ >- 0x0111c0, 0x0121f9, 0x013328, /* -23.5, -23.0, -22.5 */ >- 0x01455b, 0x0158a2, 0x016d0e, /* -22.0, -21.5, -21.0 */ >- 0x0182af, 0x019999, 0x01b1de, /* -20.5, -20.0, -19.5 */ >- 0x01cb94, 0x01e6cf, 0x0203a7, /* -19.0, -18.5, -18.0 */ >- 0x022235, 0x024293, 0x0264db, /* -17.5, -17.0, -16.5 */ >- 0x02892c, 0x02afa3, 0x02d862, /* -16.0, -15.5, -15.0 */ >- 0x03038a, 0x033142, 0x0361af, /* -14.5, -14.0, -13.5 */ >- 0x0394fa, 0x03cb50, 0x0404de, /* -13.0, -12.5, -12.0 */ >- 0x0441d5, 0x048268, 0x04c6d0, /* -11.5, -11.0, -10.5 */ >- 0x050f44, 0x055c04, 0x05ad50, /* -10.0, -09.5, -09.0 */ >- 0x06036e, 0x065ea5, 0x06bf44, /* -08.5, -08.0, -07.5 */ >- 0x07259d, 0x079207, 0x0804dc, /* -07.0, -06.5, -06.0 */ >- 0x087e80, 0x08ff59, 0x0987d5, /* -05.5, -05.0, -04.5 */ >- 0x0a1866, 0x0ab189, 0x0b53be, /* -04.0, -03.5, -03.0 */ >- 0x0bff91, 0x0cb591, 0x0d765a, /* -02.5, -02.0, -01.5 */ >- 0x0e4290, 0x0f1adf, 0x100000, /* -01.0, -00.5, 00.0 */ >- 0x10f2b4, 0x11f3c9, 0x13041a, /* +00.5, +01.0, +01.5 */ >- 0x14248e, 0x15561a, 0x1699c0, /* +02.0, +02.5, +03.0 */ >- 0x17f094, 0x195bb8, 0x1adc61, /* +03.5, +04.0, +04.5 */ >- 0x1c73d5, 0x1e236d, 0x1fec98, /* +05.0, +05.5, +06.0 */ >- 0x21d0d9, 0x23d1cd, 0x25f125, /* +06.5, +07.0, +07.5 */ >- 0x2830af, 0x2a9254, 0x2d1818, /* +08.0, +08.5, +09.0 */ >- 0x2fc420, 0x3298b0, 0x35982f, /* +09.5, +10.0, +10.5 */ >- 0x38c528, 0x3c224c, 0x3fb278, /* +11.0, +11.5, +12.0 */ >- 0x437880, 0x477828, 0x4bb446, /* +12.5, +13.0, +13.5 */ >- 0x5030a1, 0x54f106, 0x59f980, /* +14.0, +14.5, +15.0 */ >- 0x5f4e52, 0x64f403, 0x6aef5d, /* +15.5, +16.0, +16.5 */ >- 0x714575, 0x77fbaa, 0x7f17af /* +17.0, +17.5, +18.0 */ >+ TAS3001C_REG_MAX = 0x20 > }; > >-#endif /* _tas3001c_h_ */ >+#endif /* _TAS3001C_H_ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3001c_tables.c linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3001c_tables.c >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3001c_tables.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3001c_tables.c 2003-08-25 23:37:52.000000000 +0200 >@@ -0,0 +1,375 @@ >+#include "tas_common.h" >+#include "tas_eq_prefs.h" >+ >+static struct tas_drce_t eqp_0e_2_1_drce = { >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -15.33 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_0e_2_1_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, >+}; >+ >+static struct tas_eq_pref_t eqp_0e_2_1 = { >+ sample_rate: 44100, >+ device_id: 0x0e, >+ output_id: TAS_OUTPUT_EXTERNAL_SPKR, >+ speaker_id: 0x01, >+ >+ drce: &eqp_0e_2_1_drce, >+ >+ filter_count: 12, >+ biquads: eqp_0e_2_1_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_10_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -12.46 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_10_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, >+}; >+ >+static struct tas_eq_pref_t eqp_10_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x10, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_10_1_0_drce, >+ >+ filter_count: 12, >+ biquads: eqp_10_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_15_2_1_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -15.33 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_15_2_1_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, >+}; >+ >+static struct tas_eq_pref_t eqp_15_2_1 = { >+ sample_rate: 44100, >+ device_id: 0x15, >+ output_id: TAS_OUTPUT_EXTERNAL_SPKR, >+ speaker_id: 0x01, >+ >+ drce: &eqp_15_2_1_drce, >+ >+ filter_count: 12, >+ biquads: eqp_15_2_1_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_15_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: 0.0 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_15_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, >+}; >+ >+static struct tas_eq_pref_t eqp_15_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x15, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_15_1_0_drce, >+ >+ filter_count: 12, >+ biquads: eqp_15_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_0f_2_1_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -15.33 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_0f_2_1_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, >+}; >+ >+static struct tas_eq_pref_t eqp_0f_2_1 = { >+ sample_rate: 44100, >+ device_id: 0x0f, >+ output_id: TAS_OUTPUT_EXTERNAL_SPKR, >+ speaker_id: 0x01, >+ >+ drce: &eqp_0f_2_1_drce, >+ >+ filter_count: 12, >+ biquads: eqp_0f_2_1_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_0f_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -15.33 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_0f_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, >+}; >+ >+static struct tas_eq_pref_t eqp_0f_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x0f, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_0f_1_0_drce, >+ >+ filter_count: 12, >+ biquads: eqp_0f_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static uint tas3001c_master_tab[]={ >+ 0x0, 0x75, 0x9c, 0xbb, >+ 0xdb, 0xfb, 0x11e, 0x143, >+ 0x16b, 0x196, 0x1c3, 0x1f5, >+ 0x229, 0x263, 0x29f, 0x2e1, >+ 0x328, 0x373, 0x3c5, 0x41b, >+ 0x478, 0x4dc, 0x547, 0x5b8, >+ 0x633, 0x6b5, 0x740, 0x7d5, >+ 0x873, 0x91c, 0x9d2, 0xa92, >+ 0xb5e, 0xc39, 0xd22, 0xe19, >+ 0xf20, 0x1037, 0x1161, 0x129e, >+ 0x13ed, 0x1551, 0x16ca, 0x185d, >+ 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, >+ 0x21c1, 0x23fa, 0x2655, 0x28d6, >+ 0x2b7c, 0x2e4a, 0x3141, 0x3464, >+ 0x37b4, 0x3b35, 0x3ee9, 0x42d3, >+ 0x46f6, 0x4b53, 0x4ff0, 0x54ce, >+ 0x59f2, 0x5f5f, 0x6519, 0x6b24, >+ 0x7183, 0x783c, 0x7f53, 0x86cc, >+ 0x8ead, 0x96fa, 0x9fba, 0xa8f2, >+ 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, >+ 0xdee8, 0xeb75, 0xf8aa, 0x1068e, >+ 0x1152a, 0x12487, 0x134ad, 0x145a5, >+ 0x1577b, 0x16a37, 0x17df5, 0x192bd, >+ 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, >+ 0x20b55, 0x22727, 0x24456, 0x262f2, >+ 0x2830b >+}; >+ >+static uint tas3001c_mixer_tab[]={ >+ 0x0, 0x748, 0x9be, 0xbaf, >+ 0xda4, 0xfb1, 0x11de, 0x1431, >+ 0x16ad, 0x1959, 0x1c37, 0x1f4b, >+ 0x2298, 0x2628, 0x29fb, 0x2e12, >+ 0x327d, 0x3734, 0x3c47, 0x41b4, >+ 0x4787, 0x4dbe, 0x546d, 0x5b86, >+ 0x632e, 0x6b52, 0x7400, 0x7d54, >+ 0x873b, 0x91c6, 0x9d1a, 0xa920, >+ 0xb5e5, 0xc38c, 0xd21b, 0xe18f, >+ 0xf1f5, 0x1036a, 0x1160f, 0x129d6, >+ 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, >+ 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, >+ 0x21c0f, 0x23fa3, 0x26552, 0x28d64, >+ 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, >+ 0x37b44, 0x3b353, 0x3ee94, 0x42d30, >+ 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, >+ 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, >+ 0x71835, 0x783c3, 0x7f52c, 0x86cc0, >+ 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, >+ 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, >+ 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, >+ 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, >+ 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, >+ 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, >+ 0x20b542, 0x227268, 0x244564, 0x262f26, >+ 0x2830af >+}; >+ >+static uint tas3001c_treble_tab[]={ >+ 0x96, 0x95, 0x95, 0x94, >+ 0x93, 0x92, 0x92, 0x91, >+ 0x90, 0x90, 0x8f, 0x8e, >+ 0x8d, 0x8d, 0x8c, 0x8b, >+ 0x8a, 0x8a, 0x89, 0x88, >+ 0x88, 0x87, 0x86, 0x85, >+ 0x85, 0x84, 0x83, 0x83, >+ 0x82, 0x81, 0x80, 0x80, >+ 0x7f, 0x7e, 0x7e, 0x7d, >+ 0x7c, 0x7b, 0x7b, 0x7a, >+ 0x79, 0x78, 0x78, 0x77, >+ 0x76, 0x76, 0x75, 0x74, >+ 0x73, 0x73, 0x72, 0x71, >+ 0x71, 0x70, 0x6e, 0x6d, >+ 0x6d, 0x6c, 0x6b, 0x6a, >+ 0x69, 0x68, 0x67, 0x66, >+ 0x65, 0x63, 0x62, 0x62, >+ 0x60, 0x5f, 0x5d, 0x5c, >+ 0x5a, 0x58, 0x56, 0x55, >+ 0x53, 0x51, 0x4f, 0x4c, >+ 0x4a, 0x48, 0x45, 0x43, >+ 0x40, 0x3d, 0x3a, 0x37, >+ 0x35, 0x32, 0x2e, 0x2a, >+ 0x27, 0x22, 0x1e, 0x1a, >+ 0x15, 0x11, 0xc, 0x7, >+ 0x1 >+}; >+ >+static uint tas3001c_bass_tab[]={ >+ 0x86, 0x83, 0x81, 0x7f, >+ 0x7d, 0x7b, 0x79, 0x78, >+ 0x76, 0x75, 0x74, 0x72, >+ 0x71, 0x6f, 0x6e, 0x6d, >+ 0x6c, 0x6b, 0x69, 0x67, >+ 0x65, 0x64, 0x61, 0x60, >+ 0x5e, 0x5d, 0x5c, 0x5b, >+ 0x5a, 0x59, 0x58, 0x57, >+ 0x56, 0x55, 0x55, 0x54, >+ 0x53, 0x52, 0x50, 0x4f, >+ 0x4d, 0x4c, 0x4b, 0x49, >+ 0x47, 0x45, 0x44, 0x42, >+ 0x41, 0x3f, 0x3e, 0x3d, >+ 0x3c, 0x3b, 0x39, 0x38, >+ 0x37, 0x36, 0x35, 0x34, >+ 0x33, 0x31, 0x30, 0x2f, >+ 0x2e, 0x2c, 0x2b, 0x2b, >+ 0x29, 0x28, 0x27, 0x26, >+ 0x25, 0x24, 0x22, 0x21, >+ 0x20, 0x1e, 0x1c, 0x19, >+ 0x18, 0x18, 0x17, 0x16, >+ 0x15, 0x14, 0x13, 0x12, >+ 0x11, 0x10, 0xf, 0xe, >+ 0xd, 0xb, 0xa, 0x9, >+ 0x8, 0x6, 0x4, 0x2, >+ 0x1 >+}; >+ >+struct tas_gain_t tas3001c_gain = { >+ master: tas3001c_master_tab, >+ treble: tas3001c_treble_tab, >+ bass: tas3001c_bass_tab, >+ mixer: tas3001c_mixer_tab >+}; >+ >+struct tas_eq_pref_t *tas3001c_eq_prefs[]={ >+ &eqp_0e_2_1, >+ &eqp_10_1_0, >+ &eqp_15_2_1, >+ &eqp_15_1_0, >+ &eqp_0f_2_1, >+ &eqp_0f_1_0, >+ NULL >+}; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3004.c linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3004.c >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3004.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3004.c 2003-08-25 23:37:26.000000000 +0200 >@@ -0,0 +1,1173 @@ >+/* >+ * Driver for the i2c/i2s based TA3004 sound chip used >+ * on some Apple hardware. Also known as "snapper". >+ * >+ * Tobias Sargeant <tobias.sargeant@bigpond.com> >+ * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>: >+ * >+ * TODO: >+ * ----- >+ * * Enable control over input line 2 (is this connected?) >+ * * Implement sleep support (at least mute everything and >+ * * set gains to minimum during sleep) >+ * >+ */ >+ >+#include <linux/version.h> >+#include <linux/module.h> >+#include <linux/slab.h> >+#include <linux/proc_fs.h> >+#include <linux/ioport.h> >+#include <linux/sysctl.h> >+#include <linux/types.h> >+#include <linux/i2c.h> >+#include <linux/init.h> >+#include <linux/soundcard.h> >+#include <linux/interrupt.h> >+ >+#include <asm/uaccess.h> >+#include <asm/errno.h> >+#include <asm/io.h> >+#include <asm/prom.h> >+ >+#include "dmasound.h" >+#include "tas_common.h" >+#include "tas3004.h" >+ >+#include "tas_ioctl.h" >+ >+/* #define DEBUG_DRCE */ >+ >+#define TAS3004_BIQUAD_FILTER_COUNT 7 >+#define TAS3004_BIQUAD_CHANNEL_COUNT 2 >+ >+#define VOL_DEFAULT (100 * 4 / 5) >+#define INPUT_DEFAULT (100 * 4 / 5) >+#define BASS_DEFAULT (100 / 2) >+#define TREBLE_DEFAULT (100 / 2) >+ >+struct tas3004_data_t { >+ struct tas_data_t super; >+ int device_id; >+ int output_id; >+ int speaker_id; >+ struct tas_drce_t drce_state; >+}; >+ >+#define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000) >+ >+#define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000)) >+ >+ >+static const union tas_biquad_t >+tas3004_eq_unity={ >+ buf: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } >+}; >+ >+ >+static const struct tas_drce_t >+tas3004_drce_min={ >+ enable: 1, >+ above: { val: MAKE_RATIO(16,0), expand:0 }, >+ below: { val: MAKE_RATIO(2,0), expand:0 }, >+ threshold: -0x59a0, >+ energy: MAKE_TIME(0, 1700), >+ attack: MAKE_TIME(0, 1700), >+ decay: MAKE_TIME(0, 1700) >+}; >+ >+ >+static const struct tas_drce_t >+tas3004_drce_max={ >+ enable: 1, >+ above: { val: MAKE_RATIO(1,500), expand:1 }, >+ below: { val: MAKE_RATIO(2,0), expand:1 }, >+ threshold: -0x0, >+ energy: MAKE_TIME(2,400000), >+ attack: MAKE_TIME(2,400000), >+ decay: MAKE_TIME(2,400000) >+}; >+ >+ >+static const unsigned short time_constants[]={ >+ MAKE_TIME(0, 1700), >+ MAKE_TIME(0, 3500), >+ MAKE_TIME(0, 6700), >+ MAKE_TIME(0, 13000), >+ MAKE_TIME(0, 26000), >+ MAKE_TIME(0, 53000), >+ MAKE_TIME(0,106000), >+ MAKE_TIME(0,212000), >+ MAKE_TIME(0,425000), >+ MAKE_TIME(0,850000), >+ MAKE_TIME(1,700000), >+ MAKE_TIME(2,400000), >+}; >+ >+static const unsigned short above_threshold_compression_ratio[]={ >+ MAKE_RATIO( 1, 70), >+ MAKE_RATIO( 1,140), >+ MAKE_RATIO( 1,230), >+ MAKE_RATIO( 1,330), >+ MAKE_RATIO( 1,450), >+ MAKE_RATIO( 1,600), >+ MAKE_RATIO( 1,780), >+ MAKE_RATIO( 2, 0), >+ MAKE_RATIO( 2,290), >+ MAKE_RATIO( 2,670), >+ MAKE_RATIO( 3,200), >+ MAKE_RATIO( 4, 0), >+ MAKE_RATIO( 5,330), >+ MAKE_RATIO( 8, 0), >+ MAKE_RATIO(16, 0), >+}; >+ >+static const unsigned short above_threshold_expansion_ratio[]={ >+ MAKE_RATIO(1, 60), >+ MAKE_RATIO(1,130), >+ MAKE_RATIO(1,190), >+ MAKE_RATIO(1,250), >+ MAKE_RATIO(1,310), >+ MAKE_RATIO(1,380), >+ MAKE_RATIO(1,440), >+ MAKE_RATIO(1,500) >+}; >+ >+static const unsigned short below_threshold_compression_ratio[]={ >+ MAKE_RATIO(1, 70), >+ MAKE_RATIO(1,140), >+ MAKE_RATIO(1,230), >+ MAKE_RATIO(1,330), >+ MAKE_RATIO(1,450), >+ MAKE_RATIO(1,600), >+ MAKE_RATIO(1,780), >+ MAKE_RATIO(2, 0) >+}; >+ >+static const unsigned short below_threshold_expansion_ratio[]={ >+ MAKE_RATIO(1, 60), >+ MAKE_RATIO(1,130), >+ MAKE_RATIO(1,190), >+ MAKE_RATIO(1,250), >+ MAKE_RATIO(1,310), >+ MAKE_RATIO(1,380), >+ MAKE_RATIO(1,440), >+ MAKE_RATIO(1,500), >+ MAKE_RATIO(1,560), >+ MAKE_RATIO(1,630), >+ MAKE_RATIO(1,690), >+ MAKE_RATIO(1,750), >+ MAKE_RATIO(1,810), >+ MAKE_RATIO(1,880), >+ MAKE_RATIO(1,940), >+ MAKE_RATIO(2, 0) >+}; >+ >+static inline int >+search( unsigned short val, >+ const unsigned short *arr, >+ const int arrsize) { >+ /* >+ * This could be a binary search, but for small tables, >+ * a linear search is likely to be faster >+ */ >+ >+ int i; >+ >+ for (i=0; i < arrsize; i++) >+ if (arr[i] >= val) >+ goto _1; >+ return arrsize-1; >+ _1: >+ if (i == 0) >+ return 0; >+ return (arr[i]-val < val-arr[i-1]) ? i : i-1; >+} >+ >+#define SEARCH(a, b) search(a, b, ARRAY_SIZE(b)) >+ >+static inline int >+time_index(unsigned short time) { >+ return SEARCH(time, time_constants); >+} >+ >+ >+static inline int >+above_threshold_compression_index(unsigned short ratio) { >+ return SEARCH(ratio, above_threshold_compression_ratio); >+} >+ >+ >+static inline int >+above_threshold_expansion_index(unsigned short ratio) { >+ return SEARCH(ratio, above_threshold_expansion_ratio); >+} >+ >+ >+static inline int >+below_threshold_compression_index(unsigned short ratio) { >+ return SEARCH(ratio, below_threshold_compression_ratio); >+} >+ >+ >+static inline int >+below_threshold_expansion_index(unsigned short ratio) { >+ return SEARCH(ratio, below_threshold_expansion_ratio); >+} >+ >+ >+static inline unsigned char db_to_regval(short db) { >+ int r=0; >+ >+ r=(db+0x59a0) / 0x60; >+ >+ if (r < 0x91) return 0x91; >+ if (r > 0xef) return 0xef; >+ return r; >+} >+ >+ >+static inline short quantize_db(short db) { >+ return db_to_regval(db) * 0x60 - 0x59a0; >+} >+ >+ >+static inline int >+register_width(enum tas3004_reg_t r) >+{ >+ switch(r) { >+ case TAS3004_REG_MCR: >+ case TAS3004_REG_TREBLE: >+ case TAS3004_REG_BASS: >+ case TAS3004_REG_ANALOG_CTRL: >+ case TAS3004_REG_TEST1: >+ case TAS3004_REG_TEST2: >+ case TAS3004_REG_MCR2: >+ return 1; >+ >+ case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN: >+ case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN: >+ return 3; >+ >+ case TAS3004_REG_DRC: >+ case TAS3004_REG_VOLUME: >+ return 6; >+ >+ case TAS3004_REG_LEFT_MIXER: >+ case TAS3004_REG_RIGHT_MIXER: >+ return 9; >+ >+ case TAS3004_REG_TEST: >+ return 10; >+ >+ case TAS3004_REG_LEFT_BIQUAD0: >+ case TAS3004_REG_LEFT_BIQUAD1: >+ case TAS3004_REG_LEFT_BIQUAD2: >+ case TAS3004_REG_LEFT_BIQUAD3: >+ case TAS3004_REG_LEFT_BIQUAD4: >+ case TAS3004_REG_LEFT_BIQUAD5: >+ case TAS3004_REG_LEFT_BIQUAD6: >+ >+ case TAS3004_REG_RIGHT_BIQUAD0: >+ case TAS3004_REG_RIGHT_BIQUAD1: >+ case TAS3004_REG_RIGHT_BIQUAD2: >+ case TAS3004_REG_RIGHT_BIQUAD3: >+ case TAS3004_REG_RIGHT_BIQUAD4: >+ case TAS3004_REG_RIGHT_BIQUAD5: >+ case TAS3004_REG_RIGHT_BIQUAD6: >+ >+ case TAS3004_REG_LEFT_LOUD_BIQUAD: >+ case TAS3004_REG_RIGHT_LOUD_BIQUAD: >+ return 15; >+ >+ default: >+ return 0; >+ } >+} >+ >+ >+static int >+tas3004_write_register( struct tas3004_data_t *self, >+ enum tas3004_reg_t reg_num, >+ char *data, >+ uint write_mode) >+{ >+ if (reg_num==TAS3004_REG_MCR || >+ reg_num==TAS3004_REG_BASS || >+ reg_num==TAS3004_REG_TREBLE) { >+ return tas_write_byte_register(&self->super, >+ (uint)reg_num, >+ *data, >+ write_mode); >+ } else { >+ return tas_write_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num), >+ data, >+ write_mode); >+ } >+} >+ >+ >+static int >+tas3004_sync_register( struct tas3004_data_t *self, >+ enum tas3004_reg_t reg_num) >+{ >+ if (reg_num==TAS3004_REG_MCR || >+ reg_num==TAS3004_REG_BASS || >+ reg_num==TAS3004_REG_TREBLE) { >+ return tas_sync_byte_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num)); >+ } else { >+ return tas_sync_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num)); >+ } >+} >+ >+ >+static int >+tas3004_read_register( struct tas3004_data_t *self, >+ enum tas3004_reg_t reg_num, >+ char *data, >+ uint write_mode) >+{ >+ return tas_read_register(&self->super, >+ (uint)reg_num, >+ register_width(reg_num), >+ data); >+} >+ >+ >+static inline int >+tas3004_fast_load(struct tas3004_data_t *self, int fast) >+{ >+ if (fast) >+ self->super.shadow[TAS3004_REG_MCR][0] |= 0x80; >+ else >+ self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f; >+ return tas3004_sync_register(self,TAS3004_REG_MCR); >+} >+ >+ >+static uint >+tas3004_supported_mixers(struct tas3004_data_t *self) >+{ >+ return SOUND_MASK_VOLUME | >+ SOUND_MASK_PCM | >+ SOUND_MASK_ALTPCM | >+ SOUND_MASK_IMIX | >+ SOUND_MASK_TREBLE | >+ SOUND_MASK_BASS; >+} >+ >+ >+static int >+tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer) >+{ >+ switch(mixer) { >+ case SOUND_MIXER_VOLUME: >+ case SOUND_MIXER_PCM: >+ case SOUND_MIXER_ALTPCM: >+ case SOUND_MIXER_IMIX: >+ return 1; >+ default: >+ return 0; >+ } >+} >+ >+ >+static uint >+tas3004_stereo_mixers(struct tas3004_data_t *self) >+{ >+ uint r = tas3004_supported_mixers(self); >+ uint i; >+ >+ for (i=1; i<SOUND_MIXER_NRDEVICES; i++) >+ if (r&(1<<i) && !tas3004_mixer_is_stereo(self,i)) >+ r &= ~(1<<i); >+ return r; >+} >+ >+ >+static int >+tas3004_get_mixer_level(struct tas3004_data_t *self, int mixer, uint *level) >+{ >+ if (!self) >+ return -1; >+ >+ *level = self->super.mixer[mixer]; >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) >+{ >+ int rc; >+ tas_shadow_t *shadow; >+ uint temp; >+ uint offset=0; >+ >+ if (!self) >+ return -1; >+ >+ shadow = self->super.shadow; >+ >+ if (!tas3004_mixer_is_stereo(self,mixer)) >+ level = tas_mono_to_stereo(level); >+ switch(mixer) { >+ case SOUND_MIXER_VOLUME: >+ temp = tas3004_gain.master[level&0xff]; >+ SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp); >+ temp = tas3004_gain.master[(level>>8)&0xff]; >+ SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp); >+ rc = tas3004_sync_register(self,TAS3004_REG_VOLUME); >+ break; >+ case SOUND_MIXER_IMIX: >+ offset += 3; >+ case SOUND_MIXER_ALTPCM: >+ offset += 3; >+ case SOUND_MIXER_PCM: >+ /* >+ * Don't load these in fast mode. The documentation >+ * says it can be done in either mode, but testing it >+ * shows that fast mode produces ugly clicking. >+ */ >+ /* tas3004_fast_load(self,1); */ >+ temp = tas3004_gain.mixer[level&0xff]; >+ SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp); >+ temp = tas3004_gain.mixer[(level>>8)&0xff]; >+ SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp); >+ rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); >+ if (rc == 0) >+ rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); >+ /* tas3004_fast_load(self,0); */ >+ break; >+ case SOUND_MIXER_TREBLE: >+ temp = tas3004_gain.treble[level&0xff]; >+ shadow[TAS3004_REG_TREBLE][0]=temp&0xff; >+ rc = tas3004_sync_register(self,TAS3004_REG_TREBLE); >+ break; >+ case SOUND_MIXER_BASS: >+ temp = tas3004_gain.bass[level&0xff]; >+ shadow[TAS3004_REG_BASS][0]=temp&0xff; >+ rc = tas3004_sync_register(self,TAS3004_REG_BASS); >+ break; >+ default: >+ rc = -1; >+ break; >+ } >+ if (rc < 0) >+ return rc; >+ self->super.mixer[mixer] = level; >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_leave_sleep(struct tas3004_data_t *self) >+{ >+ unsigned char mcr = (1<<6)+(2<<4)+(2<<2); >+ >+ if (!self) >+ return -1; >+ >+ /* Make sure something answers on the i2c bus */ >+ if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, >+ WRITE_NORMAL | FORCE_WRITE) < 0) >+ return -1; >+ >+ tas3004_fast_load(self, 1); >+ >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); >+ >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); >+ >+ tas3004_fast_load(self, 0); >+ >+ (void)tas3004_sync_register(self,TAS3004_REG_VOLUME); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); >+ (void)tas3004_sync_register(self,TAS3004_REG_TREBLE); >+ (void)tas3004_sync_register(self,TAS3004_REG_BASS); >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_enter_sleep(struct tas3004_data_t *self) >+{ >+ if (!self) >+ return -1; >+ return 0; >+} >+ >+ >+static int >+tas3004_sync_biquad( struct tas3004_data_t *self, >+ u_int channel, >+ u_int filter) >+{ >+ enum tas3004_reg_t reg; >+ >+ if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || >+ filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; >+ >+ reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; >+ >+ return tas3004_sync_register(self,reg); >+} >+ >+ >+static int >+tas3004_write_biquad_shadow( struct tas3004_data_t *self, >+ u_int channel, >+ u_int filter, >+ const union tas_biquad_t *biquad) >+{ >+ tas_shadow_t *shadow=self->super.shadow; >+ enum tas3004_reg_t reg; >+ >+ if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || >+ filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; >+ >+ reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; >+ >+ SET_4_20(shadow[reg], 0,biquad->coeff.b0); >+ SET_4_20(shadow[reg], 3,biquad->coeff.b1); >+ SET_4_20(shadow[reg], 6,biquad->coeff.b2); >+ SET_4_20(shadow[reg], 9,biquad->coeff.a1); >+ SET_4_20(shadow[reg],12,biquad->coeff.a2); >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_write_biquad( struct tas3004_data_t *self, >+ u_int channel, >+ u_int filter, >+ const union tas_biquad_t *biquad) >+{ >+ int rc; >+ >+ rc=tas3004_write_biquad_shadow(self, channel, filter, biquad); >+ if (rc < 0) return rc; >+ >+ return tas3004_sync_biquad(self, channel, filter); >+} >+ >+ >+static int >+tas3004_write_biquad_list( struct tas3004_data_t *self, >+ u_int filter_count, >+ u_int flags, >+ struct tas_biquad_ctrl_t *biquads) >+{ >+ int i; >+ int rc; >+ >+ if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); >+ >+ for (i=0; i<filter_count; i++) { >+ rc=tas3004_write_biquad(self, >+ biquads[i].channel, >+ biquads[i].filter, >+ &biquads[i].data); >+ if (rc < 0) break; >+ } >+ >+ if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,0); >+ >+ return rc; >+} >+ >+ >+static int >+tas3004_read_biquad( struct tas3004_data_t *self, >+ u_int channel, >+ u_int filter, >+ union tas_biquad_t *biquad) >+{ >+ tas_shadow_t *shadow=self->super.shadow; >+ enum tas3004_reg_t reg; >+ >+ if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || >+ filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; >+ >+ reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; >+ >+ biquad->coeff.b0=GET_4_20(shadow[reg], 0); >+ biquad->coeff.b1=GET_4_20(shadow[reg], 3); >+ biquad->coeff.b2=GET_4_20(shadow[reg], 6); >+ biquad->coeff.a1=GET_4_20(shadow[reg], 9); >+ biquad->coeff.a2=GET_4_20(shadow[reg],12); >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_eq_rw( struct tas3004_data_t *self, >+ u_int cmd, >+ u_long arg) >+{ >+ int rc; >+ struct tas_biquad_ctrl_t biquad; >+ >+ if (copy_from_user((void *)&biquad, (const void *)arg, sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+ if (cmd & SIOC_IN) { >+ rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ } >+ >+ if (cmd & SIOC_OUT) { >+ rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ >+ if (copy_to_user((void *)arg, (const void *)&biquad, sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+ } >+ return 0; >+} >+ >+ >+static int >+tas3004_eq_list_rw( struct tas3004_data_t *self, >+ u_int cmd, >+ u_long arg) >+{ >+ int rc = 0; >+ int filter_count; >+ int flags; >+ int i,j; >+ char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT]; >+ struct tas_biquad_ctrl_t biquad; >+ >+ memset(sync_required,0,sizeof(sync_required)); >+ >+ if (copy_from_user((void *)&filter_count, >+ (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,filter_count), >+ sizeof(int))) { >+ return -EFAULT; >+ } >+ >+ if (copy_from_user((void *)&flags, >+ (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t,flags), >+ sizeof(int))) { >+ return -EFAULT; >+ } >+ >+ if (cmd & SIOC_IN) { >+ } >+ >+ for (i=0; i < filter_count; i++) { >+ if (copy_from_user((void *)&biquad, >+ (const void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), >+ sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+ if (cmd & SIOC_IN) { >+ sync_required[biquad.channel][biquad.filter]=1; >+ rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ } >+ >+ if (cmd & SIOC_OUT) { >+ rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); >+ if (rc != 0) return rc; >+ >+ if (copy_to_user((void *)arg + offsetof(struct tas_biquad_ctrl_list_t, biquads[i]), >+ (const void *)&biquad, >+ sizeof(struct tas_biquad_ctrl_t))) { >+ return -EFAULT; >+ } >+ } >+ } >+ >+ if (cmd & SIOC_IN) { >+ /* >+ * This is OK for the tas3004. For the >+ * tas3001c, going into fast load mode causes >+ * the treble and bass to be reset to 0dB, and >+ * volume controls to be muted. >+ */ >+ if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); >+ for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) { >+ for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) { >+ if (sync_required[i][j]) { >+ rc=tas3004_sync_biquad(self, i, j); >+ if (rc < 0) goto out; >+ } >+ } >+ } >+ out: >+ if (flags & TAS_BIQUAD_FAST_LOAD) >+ tas3004_fast_load(self,0); >+ } >+ >+ return rc; >+} >+ >+ >+static int >+tas3004_update_drce( struct tas3004_data_t *self, >+ int flags, >+ struct tas_drce_t *drce) >+{ >+ tas_shadow_t *shadow; >+ int i; >+ shadow=self->super.shadow; >+ >+ if (flags & TAS_DRCE_ABOVE_RATIO) { >+ self->drce_state.above.expand = drce->above.expand; >+ if (drce->above.val == (1<<8)) { >+ self->drce_state.above.val = 1<<8; >+ shadow[TAS3004_REG_DRC][0] = 0x02; >+ >+ } else if (drce->above.expand) { >+ i=above_threshold_expansion_index(drce->above.val); >+ self->drce_state.above.val=above_threshold_expansion_ratio[i]; >+ shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3); >+ } else { >+ i=above_threshold_compression_index(drce->above.val); >+ self->drce_state.above.val=above_threshold_compression_ratio[i]; >+ shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3); >+ } >+ } >+ >+ if (flags & TAS_DRCE_BELOW_RATIO) { >+ self->drce_state.below.expand = drce->below.expand; >+ if (drce->below.val == (1<<8)) { >+ self->drce_state.below.val = 1<<8; >+ shadow[TAS3004_REG_DRC][1] = 0x02; >+ >+ } else if (drce->below.expand) { >+ i=below_threshold_expansion_index(drce->below.val); >+ self->drce_state.below.val=below_threshold_expansion_ratio[i]; >+ shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3); >+ } else { >+ i=below_threshold_compression_index(drce->below.val); >+ self->drce_state.below.val=below_threshold_compression_ratio[i]; >+ shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3); >+ } >+ } >+ >+ if (flags & TAS_DRCE_THRESHOLD) { >+ self->drce_state.threshold=quantize_db(drce->threshold); >+ shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold); >+ } >+ >+ if (flags & TAS_DRCE_ENERGY) { >+ i=time_index(drce->energy); >+ self->drce_state.energy=time_constants[i]; >+ shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4); >+ } >+ >+ if (flags & TAS_DRCE_ATTACK) { >+ i=time_index(drce->attack); >+ self->drce_state.attack=time_constants[i]; >+ shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4); >+ } >+ >+ if (flags & TAS_DRCE_DECAY) { >+ i=time_index(drce->decay); >+ self->drce_state.decay=time_constants[i]; >+ shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4); >+ } >+ >+ if (flags & TAS_DRCE_ENABLE) { >+ self->drce_state.enable = drce->enable; >+ } >+ >+ if (!self->drce_state.enable) { >+ shadow[TAS3004_REG_DRC][0] |= 0x01; >+ } >+ >+#ifdef DEBUG_DRCE >+ printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", >+ self->drce_state.enable, >+ self->drce_state.above.expand,self->drce_state.above.val, >+ self->drce_state.below.expand,self->drce_state.below.val, >+ self->drce_state.threshold, >+ self->drce_state.energy, >+ self->drce_state.attack, >+ self->drce_state.decay); >+ >+ printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n", >+ (unsigned char)shadow[TAS3004_REG_DRC][0], >+ (unsigned char)shadow[TAS3004_REG_DRC][1], >+ (unsigned char)shadow[TAS3004_REG_DRC][2], >+ (unsigned char)shadow[TAS3004_REG_DRC][3], >+ (unsigned char)shadow[TAS3004_REG_DRC][4], >+ (unsigned char)shadow[TAS3004_REG_DRC][5]); >+#endif >+ >+ return tas3004_sync_register(self, TAS3004_REG_DRC); >+} >+ >+ >+static int >+tas3004_drce_rw( struct tas3004_data_t *self, >+ u_int cmd, >+ u_long arg) >+{ >+ int rc; >+ struct tas_drce_ctrl_t drce_ctrl; >+ >+ if (copy_from_user((void *)&drce_ctrl, >+ (const void *)arg, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+#ifdef DEBUG_DRCE >+ printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", >+ drce_ctrl.flags, >+ drce_ctrl.data.enable, >+ drce_ctrl.data.above.expand,drce_ctrl.data.above.val, >+ drce_ctrl.data.below.expand,drce_ctrl.data.below.val, >+ drce_ctrl.data.threshold, >+ drce_ctrl.data.energy, >+ drce_ctrl.data.attack, >+ drce_ctrl.data.decay); >+#endif >+ >+ if (cmd & SIOC_IN) { >+ rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); >+ if (rc < 0) return rc; >+ } >+ >+ if (cmd & SIOC_OUT) { >+ if (drce_ctrl.flags & TAS_DRCE_ENABLE) >+ drce_ctrl.data.enable = self->drce_state.enable; >+ if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) >+ drce_ctrl.data.above = self->drce_state.above; >+ if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) >+ drce_ctrl.data.below = self->drce_state.below; >+ if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) >+ drce_ctrl.data.threshold = self->drce_state.threshold; >+ if (drce_ctrl.flags & TAS_DRCE_ENERGY) >+ drce_ctrl.data.energy = self->drce_state.energy; >+ if (drce_ctrl.flags & TAS_DRCE_ATTACK) >+ drce_ctrl.data.attack = self->drce_state.attack; >+ if (drce_ctrl.flags & TAS_DRCE_DECAY) >+ drce_ctrl.data.decay = self->drce_state.decay; >+ >+ if (copy_to_user((void *)arg, >+ (const void *)&drce_ctrl, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ } >+ >+ return 0; >+} >+ >+ >+static void >+tas3004_update_device_parameters(struct tas3004_data_t *self) >+{ >+ char data; >+ int i; >+ >+ if (!self) return; >+ >+ if (self->output_id == TAS_OUTPUT_HEADPHONES) { >+ /* turn on allPass when headphones are plugged in */ >+ data = 0x02; >+ } else { >+ data = 0x00; >+ } >+ >+ tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE); >+ >+ for (i=0; tas3004_eq_prefs[i]; i++) { >+ struct tas_eq_pref_t *eq = tas3004_eq_prefs[i]; >+ >+ if (eq->device_id == self->device_id && >+ (eq->output_id == 0 || eq->output_id == self->output_id) && >+ (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { >+ >+ tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce); >+ tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); >+ >+ break; >+ } >+ } >+} >+ >+static void >+tas3004_device_change_handler(void *self) >+{ >+ if (!self) return; >+ >+ tas3004_update_device_parameters((struct tas3004_data_t *)self); >+} >+ >+static struct tq_struct device_change_task; >+ >+static int >+tas3004_output_device_change( struct tas3004_data_t *self, >+ int device_id, >+ int output_id, >+ int speaker_id) >+{ >+ self->device_id=device_id; >+ self->output_id=output_id; >+ self->speaker_id=speaker_id; >+ >+ schedule_task(&device_change_task); >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_device_ioctl( struct tas3004_data_t *self, >+ u_int cmd, >+ u_long arg) >+{ >+ switch (cmd) { >+ case TAS_READ_EQ: >+ case TAS_WRITE_EQ: >+ return tas3004_eq_rw(self, cmd, arg); >+ >+ case TAS_READ_EQ_LIST: >+ case TAS_WRITE_EQ_LIST: >+ return tas3004_eq_list_rw(self, cmd, arg); >+ >+ case TAS_READ_EQ_FILTER_COUNT: >+ put_user(TAS3004_BIQUAD_FILTER_COUNT, (uint *)(arg)); >+ return 0; >+ >+ case TAS_READ_EQ_CHANNEL_COUNT: >+ put_user(TAS3004_BIQUAD_CHANNEL_COUNT, (uint *)(arg)); >+ return 0; >+ >+ case TAS_READ_DRCE: >+ case TAS_WRITE_DRCE: >+ return tas3004_drce_rw(self, cmd, arg); >+ >+ case TAS_READ_DRCE_CAPS: >+ put_user(TAS_DRCE_ENABLE | >+ TAS_DRCE_ABOVE_RATIO | >+ TAS_DRCE_BELOW_RATIO | >+ TAS_DRCE_THRESHOLD | >+ TAS_DRCE_ENERGY | >+ TAS_DRCE_ATTACK | >+ TAS_DRCE_DECAY, >+ (uint *)(arg)); >+ return 0; >+ >+ case TAS_READ_DRCE_MIN: >+ case TAS_READ_DRCE_MAX: { >+ struct tas_drce_ctrl_t drce_ctrl; >+ const struct tas_drce_t *drce_copy; >+ >+ if (copy_from_user((void *)&drce_ctrl, >+ (const void *)arg, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ >+ if (cmd == TAS_READ_DRCE_MIN) { >+ drce_copy=&tas3004_drce_min; >+ } else { >+ drce_copy=&tas3004_drce_max; >+ } >+ >+ if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) { >+ drce_ctrl.data.above=drce_copy->above; >+ } >+ if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) { >+ drce_ctrl.data.below=drce_copy->below; >+ } >+ if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { >+ drce_ctrl.data.threshold=drce_copy->threshold; >+ } >+ if (drce_ctrl.flags & TAS_DRCE_ENERGY) { >+ drce_ctrl.data.energy=drce_copy->energy; >+ } >+ if (drce_ctrl.flags & TAS_DRCE_ATTACK) { >+ drce_ctrl.data.attack=drce_copy->attack; >+ } >+ if (drce_ctrl.flags & TAS_DRCE_DECAY) { >+ drce_ctrl.data.decay=drce_copy->decay; >+ } >+ >+ if (copy_to_user((void *)arg, >+ (const void *)&drce_ctrl, >+ sizeof(struct tas_drce_ctrl_t))) { >+ return -EFAULT; >+ } >+ } >+ } >+ >+ return -EINVAL; >+} >+ >+ >+static int >+tas3004_init_mixer(struct tas3004_data_t *self) >+{ >+ unsigned char mcr = (1<<6)+(2<<4)+(2<<2); >+ >+ /* Make sure something answers on the i2c bus */ >+ if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, >+ WRITE_NORMAL | FORCE_WRITE) < 0) >+ return -1; >+ >+ tas3004_fast_load(self, 1); >+ >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); >+ (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); >+ >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); >+ (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); >+ >+ tas3004_sync_register(self, TAS3004_REG_DRC); >+ >+ tas3004_sync_register(self, TAS3004_REG_MCR2); >+ >+ tas3004_fast_load(self, 0); >+ >+ tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); >+ tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); >+ tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); >+ tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); >+ >+ tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); >+ tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_uninit_mixer(struct tas3004_data_t *self) >+{ >+ tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); >+ tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0); >+ tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); >+ tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); >+ >+ tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0); >+ tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); >+ >+ return 0; >+} >+ >+ >+static int >+tas3004_init(struct i2c_client *client) >+{ >+ char drce_init[]={ 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 }; >+ char mcr2 = 0; >+ >+ struct tas3004_data_t *self; >+ int i, j; >+ >+ self = kmalloc(sizeof(struct tas3004_data_t) + >+ TAS3004_REG_MAX * sizeof(tas_shadow_t), >+ GFP_KERNEL); >+ if (self == NULL) >+ return -ENOMEM; >+ >+ memset(self, >+ 0, >+ sizeof(struct tas3004_data_t) + >+ TAS3004_REG_MAX * sizeof(tas_shadow_t)); >+ >+ client->data = (void *)self; >+ >+ self->super.client = client; >+ self->super.shadow = (tas_shadow_t *)(self+1); >+ >+ self->output_id=TAS_OUTPUT_HEADPHONES; >+ self->device_id=0; >+ self->speaker_id=0; >+ >+ for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) { >+ for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) { >+ tas3004_write_biquad_shadow(self, i, j, &tas3004_eq_unity); >+ } >+ } >+ >+ tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW); >+ tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW); >+ >+ INIT_TQUEUE(&device_change_task, tas3004_device_change_handler, (void *)self); >+ >+ return 0; >+} >+ >+ >+static void >+tas3004_uninit(struct tas3004_data_t *self) >+{ >+ tas3004_uninit_mixer(self); >+ kfree(self); >+} >+ >+ >+struct tas_driver_hooks_t tas3004_hooks = { >+ init: (tas_hook_init_t)tas3004_init, >+ post_init: (tas_hook_post_init_t)tas3004_init_mixer, >+ uninit: (tas_hook_uninit_t)tas3004_uninit, >+ >+ get_mixer_level: (tas_hook_get_mixer_level_t)tas3004_get_mixer_level, >+ set_mixer_level: (tas_hook_set_mixer_level_t)tas3004_set_mixer_level, >+ >+ enter_sleep: (tas_hook_enter_sleep_t)tas3004_enter_sleep, >+ leave_sleep: (tas_hook_leave_sleep_t)tas3004_leave_sleep, >+ >+ supported_mixers: (tas_hook_supported_mixers_t)tas3004_supported_mixers, >+ mixer_is_stereo: (tas_hook_mixer_is_stereo_t)tas3004_mixer_is_stereo, >+ stereo_mixers: (tas_hook_stereo_mixers_t)tas3004_stereo_mixers, >+ >+ output_device_change: (tas_hook_output_device_change_t)tas3004_output_device_change, >+ >+ device_ioctl: (tas_hook_device_ioctl_t)tas3004_device_ioctl >+}; >+ >+/* >+ * Local Variables: >+ * tab-width: 8 >+ * indent-tabs-mode: t >+ * c-basic-offset: 8 >+ * End: >+ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3004.h linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3004.h >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3004.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3004.h 2003-08-25 23:37:44.000000000 +0200 >@@ -0,0 +1,77 @@ >+/* >+ * Header file for the i2c/i2s based TA3004 sound chip used >+ * on some Apple hardware. Also known as "tumbler". >+ * >+ * This file is subject to the terms and conditions of the GNU General Public >+ * License. See the file COPYING in the main directory of this archive >+ * for more details. >+ * >+ * Written by Christopher C. Chimelis <chris@debian.org> >+ */ >+ >+#ifndef _TAS3004_H_ >+#define _TAS3004_H_ >+ >+#include <linux/types.h> >+ >+#include "tas_common.h" >+#include "tas_eq_prefs.h" >+ >+/* >+ * Macros that correspond to the registers that we write to >+ * when setting the various values. >+ */ >+ >+#define TAS3004_VERSION "0.3" >+#define TAS3004_DATE "20011214" >+ >+#define I2C_DRIVERNAME_TAS3004 "TAS3004 driver V " TAS3004_VERSION >+#define I2C_DRIVERID_TAS3004 (I2C_DRIVERID_TAS_BASE+1) >+ >+extern struct tas_driver_hooks_t tas3004_hooks; >+extern struct tas_gain_t tas3004_gain; >+extern struct tas_eq_pref_t *tas3004_eq_prefs[]; >+ >+enum tas3004_reg_t { >+ TAS3004_REG_MCR = 0x01, >+ TAS3004_REG_DRC = 0x02, >+ >+ TAS3004_REG_VOLUME = 0x04, >+ TAS3004_REG_TREBLE = 0x05, >+ TAS3004_REG_BASS = 0x06, >+ TAS3004_REG_LEFT_MIXER = 0x07, >+ TAS3004_REG_RIGHT_MIXER = 0x08, >+ >+ TAS3004_REG_LEFT_BIQUAD0 = 0x0a, >+ TAS3004_REG_LEFT_BIQUAD1 = 0x0b, >+ TAS3004_REG_LEFT_BIQUAD2 = 0x0c, >+ TAS3004_REG_LEFT_BIQUAD3 = 0x0d, >+ TAS3004_REG_LEFT_BIQUAD4 = 0x0e, >+ TAS3004_REG_LEFT_BIQUAD5 = 0x0f, >+ TAS3004_REG_LEFT_BIQUAD6 = 0x10, >+ >+ TAS3004_REG_RIGHT_BIQUAD0 = 0x13, >+ TAS3004_REG_RIGHT_BIQUAD1 = 0x14, >+ TAS3004_REG_RIGHT_BIQUAD2 = 0x15, >+ TAS3004_REG_RIGHT_BIQUAD3 = 0x16, >+ TAS3004_REG_RIGHT_BIQUAD4 = 0x17, >+ TAS3004_REG_RIGHT_BIQUAD5 = 0x18, >+ TAS3004_REG_RIGHT_BIQUAD6 = 0x19, >+ >+ TAS3004_REG_LEFT_LOUD_BIQUAD = 0x21, >+ TAS3004_REG_RIGHT_LOUD_BIQUAD = 0x22, >+ >+ TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN = 0x23, >+ TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN = 0x24, >+ >+ TAS3004_REG_TEST = 0x29, >+ >+ TAS3004_REG_ANALOG_CTRL = 0x40, >+ TAS3004_REG_TEST1 = 0x41, >+ TAS3004_REG_TEST2 = 0x42, >+ TAS3004_REG_MCR2 = 0x43, >+ >+ TAS3004_REG_MAX = 0x44 >+}; >+ >+#endif /* _TAS3004_H_ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3004_tables.c linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3004_tables.c >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas3004_tables.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas3004_tables.c 2003-08-25 23:37:44.000000000 +0200 >@@ -0,0 +1,301 @@ >+#include "tas3004.h" >+#include "tas_eq_prefs.h" >+ >+static struct tas_drce_t eqp_17_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -19.12 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_17_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, >+ { channel: 0, filter: 6, data: { coeff: { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, >+ { channel: 1, filter: 6, data: { coeff: { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } } >+}; >+ >+static struct tas_eq_pref_t eqp_17_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x17, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_17_1_0_drce, >+ >+ filter_count: 14, >+ biquads: eqp_17_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_18_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -13.14 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_18_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, >+ { channel: 0, filter: 6, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, >+ { channel: 1, filter: 6, data: { coeff: { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } } >+}; >+ >+static struct tas_eq_pref_t eqp_18_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x18, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_18_1_0_drce, >+ >+ filter_count: 14, >+ biquads: eqp_18_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_1a_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -10.75 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_1a_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, >+ { channel: 0, filter: 6, data: { coeff: { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, >+ { channel: 1, filter: 6, data: { coeff: { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } } >+}; >+ >+static struct tas_eq_pref_t eqp_1a_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x1a, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_1a_1_0_drce, >+ >+ filter_count: 14, >+ biquads: eqp_1a_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static struct tas_drce_t eqp_1c_1_0_drce={ >+ enable: 1, >+ above: { val: 3.0 * (1<<8), expand: 0 }, >+ below: { val: 1.0 * (1<<8), expand: 0 }, >+ threshold: -14.34 * (1<<8), >+ energy: 2.4 * (1<<12), >+ attack: 0.013 * (1<<12), >+ decay: 0.212 * (1<<12), >+}; >+ >+static struct tas_biquad_ctrl_t eqp_1c_1_0_biquads[]={ >+ { channel: 0, filter: 0, data: { coeff: { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, >+ { channel: 0, filter: 1, data: { coeff: { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, >+ { channel: 0, filter: 2, data: { coeff: { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, >+ { channel: 0, filter: 3, data: { coeff: { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, >+ { channel: 0, filter: 4, data: { coeff: { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, >+ { channel: 0, filter: 5, data: { coeff: { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, >+ { channel: 0, filter: 6, data: { coeff: { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } }, >+ >+ { channel: 1, filter: 0, data: { coeff: { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, >+ { channel: 1, filter: 1, data: { coeff: { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, >+ { channel: 1, filter: 2, data: { coeff: { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, >+ { channel: 1, filter: 3, data: { coeff: { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, >+ { channel: 1, filter: 4, data: { coeff: { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, >+ { channel: 1, filter: 5, data: { coeff: { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, >+ { channel: 1, filter: 6, data: { coeff: { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } } >+}; >+ >+static struct tas_eq_pref_t eqp_1c_1_0 = { >+ sample_rate: 44100, >+ device_id: 0x1c, >+ output_id: TAS_OUTPUT_INTERNAL_SPKR, >+ speaker_id: 0x00, >+ >+ drce: &eqp_1c_1_0_drce, >+ >+ filter_count: 14, >+ biquads: eqp_1c_1_0_biquads >+}; >+ >+/* ======================================================================== */ >+ >+static uint tas3004_master_tab[]={ >+ 0x0, 0x75, 0x9c, 0xbb, >+ 0xdb, 0xfb, 0x11e, 0x143, >+ 0x16b, 0x196, 0x1c3, 0x1f5, >+ 0x229, 0x263, 0x29f, 0x2e1, >+ 0x328, 0x373, 0x3c5, 0x41b, >+ 0x478, 0x4dc, 0x547, 0x5b8, >+ 0x633, 0x6b5, 0x740, 0x7d5, >+ 0x873, 0x91c, 0x9d2, 0xa92, >+ 0xb5e, 0xc39, 0xd22, 0xe19, >+ 0xf20, 0x1037, 0x1161, 0x129e, >+ 0x13ed, 0x1551, 0x16ca, 0x185d, >+ 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, >+ 0x21c1, 0x23fa, 0x2655, 0x28d6, >+ 0x2b7c, 0x2e4a, 0x3141, 0x3464, >+ 0x37b4, 0x3b35, 0x3ee9, 0x42d3, >+ 0x46f6, 0x4b53, 0x4ff0, 0x54ce, >+ 0x59f2, 0x5f5f, 0x6519, 0x6b24, >+ 0x7183, 0x783c, 0x7f53, 0x86cc, >+ 0x8ead, 0x96fa, 0x9fba, 0xa8f2, >+ 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, >+ 0xdee8, 0xeb75, 0xf8aa, 0x1068e, >+ 0x1152a, 0x12487, 0x134ad, 0x145a5, >+ 0x1577b, 0x16a37, 0x17df5, 0x192bd, >+ 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, >+ 0x20b55, 0x22727, 0x24456, 0x262f2, >+ 0x2830b >+}; >+ >+static uint tas3004_mixer_tab[]={ >+ 0x0, 0x748, 0x9be, 0xbaf, >+ 0xda4, 0xfb1, 0x11de, 0x1431, >+ 0x16ad, 0x1959, 0x1c37, 0x1f4b, >+ 0x2298, 0x2628, 0x29fb, 0x2e12, >+ 0x327d, 0x3734, 0x3c47, 0x41b4, >+ 0x4787, 0x4dbe, 0x546d, 0x5b86, >+ 0x632e, 0x6b52, 0x7400, 0x7d54, >+ 0x873b, 0x91c6, 0x9d1a, 0xa920, >+ 0xb5e5, 0xc38c, 0xd21b, 0xe18f, >+ 0xf1f5, 0x1036a, 0x1160f, 0x129d6, >+ 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, >+ 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, >+ 0x21c0f, 0x23fa3, 0x26552, 0x28d64, >+ 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, >+ 0x37b44, 0x3b353, 0x3ee94, 0x42d30, >+ 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, >+ 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, >+ 0x71835, 0x783c3, 0x7f52c, 0x86cc0, >+ 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, >+ 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, >+ 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, >+ 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, >+ 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, >+ 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, >+ 0x20b542, 0x227268, 0x244564, 0x262f26, >+ 0x2830af >+}; >+ >+static uint tas3004_treble_tab[]={ >+ 0x96, 0x95, 0x95, 0x94, >+ 0x93, 0x92, 0x92, 0x91, >+ 0x90, 0x90, 0x8f, 0x8e, >+ 0x8d, 0x8d, 0x8c, 0x8b, >+ 0x8a, 0x8a, 0x89, 0x88, >+ 0x88, 0x87, 0x86, 0x85, >+ 0x85, 0x84, 0x83, 0x83, >+ 0x82, 0x81, 0x80, 0x80, >+ 0x7f, 0x7e, 0x7e, 0x7d, >+ 0x7c, 0x7b, 0x7b, 0x7a, >+ 0x79, 0x78, 0x78, 0x77, >+ 0x76, 0x76, 0x75, 0x74, >+ 0x73, 0x73, 0x72, 0x71, >+ 0x71, 0x68, 0x45, 0x5b, >+ 0x6d, 0x6c, 0x6b, 0x6a, >+ 0x69, 0x68, 0x67, 0x66, >+ 0x65, 0x63, 0x62, 0x62, >+ 0x60, 0x5e, 0x5c, 0x5b, >+ 0x59, 0x57, 0x55, 0x53, >+ 0x52, 0x4f, 0x4d, 0x4a, >+ 0x48, 0x46, 0x43, 0x40, >+ 0x3d, 0x3a, 0x36, 0x33, >+ 0x2f, 0x2c, 0x27, 0x23, >+ 0x1f, 0x1a, 0x15, 0xf, >+ 0x8, 0x5, 0x2, 0x1, >+ 0x1 >+}; >+ >+static uint tas3004_bass_tab[]={ >+ 0x96, 0x95, 0x95, 0x94, >+ 0x93, 0x92, 0x92, 0x91, >+ 0x90, 0x90, 0x8f, 0x8e, >+ 0x8d, 0x8d, 0x8c, 0x8b, >+ 0x8a, 0x8a, 0x89, 0x88, >+ 0x88, 0x87, 0x86, 0x85, >+ 0x85, 0x84, 0x83, 0x83, >+ 0x82, 0x81, 0x80, 0x80, >+ 0x7f, 0x7e, 0x7e, 0x7d, >+ 0x7c, 0x7b, 0x7b, 0x7a, >+ 0x79, 0x78, 0x78, 0x77, >+ 0x76, 0x76, 0x75, 0x74, >+ 0x73, 0x73, 0x72, 0x71, >+ 0x70, 0x6f, 0x6e, 0x6d, >+ 0x6c, 0x6b, 0x6a, 0x6a, >+ 0x69, 0x67, 0x66, 0x66, >+ 0x65, 0x63, 0x62, 0x62, >+ 0x61, 0x60, 0x5e, 0x5d, >+ 0x5b, 0x59, 0x57, 0x55, >+ 0x53, 0x51, 0x4f, 0x4c, >+ 0x4a, 0x48, 0x46, 0x44, >+ 0x41, 0x3e, 0x3b, 0x38, >+ 0x36, 0x33, 0x2f, 0x2b, >+ 0x28, 0x24, 0x20, 0x1c, >+ 0x17, 0x12, 0xd, 0x7, >+ 0x1 >+}; >+ >+struct tas_gain_t tas3004_gain={ >+ master: tas3004_master_tab, >+ treble: tas3004_treble_tab, >+ bass: tas3004_bass_tab, >+ mixer: tas3004_mixer_tab >+}; >+ >+struct tas_eq_pref_t *tas3004_eq_prefs[]={ >+ &eqp_17_1_0, >+ &eqp_18_1_0, >+ &eqp_1a_1_0, >+ &eqp_1c_1_0, >+ NULL >+}; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_common.c linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_common.c >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_common.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_common.c 2003-08-25 23:37:28.000000000 +0200 >@@ -0,0 +1,256 @@ >+#include <linux/version.h> >+#include <linux/module.h> >+#include <linux/slab.h> >+#include <linux/proc_fs.h> >+#include <linux/ioport.h> >+#include <linux/sysctl.h> >+#include <linux/types.h> >+#include <linux/i2c.h> >+#include <linux/init.h> >+#include <linux/soundcard.h> >+#include <asm/uaccess.h> >+#include <asm/errno.h> >+#include <asm/io.h> >+#include <asm/prom.h> >+ >+#include "tas_common.h" >+ >+#define CALL0(proc) \ >+ do { \ >+ struct tas_data_t *self; \ >+ if (!tas_client || driver_hooks == NULL) \ >+ return -1; \ >+ self = (struct tas_data_t *)tas_client->data; \ >+ if (driver_hooks->proc) \ >+ return driver_hooks->proc(self); \ >+ else \ >+ return -EINVAL; \ >+ } while (0) >+ >+#define CALL(proc,arg...) \ >+ do { \ >+ struct tas_data_t *self; \ >+ if (!tas_client || driver_hooks == NULL) \ >+ return -1; \ >+ self = (struct tas_data_t *)tas_client->data; \ >+ if (driver_hooks->proc) \ >+ return driver_hooks->proc(self, ## arg); \ >+ else \ >+ return -EINVAL; \ >+ } while (0) >+ >+ >+static u8 tas_i2c_address = 0x34; >+static struct i2c_client * tas_client = NULL; >+ >+static int tas_initialized = 0; >+static struct device_node* tas_node = NULL; >+ >+static int tas_attach_adapter(struct i2c_adapter *); >+static int tas_detach_client(struct i2c_client *); >+ >+struct i2c_driver tas_driver = { >+ name: "", >+ id: 0, >+ flags: I2C_DF_NOTIFY, >+ attach_adapter: &tas_attach_adapter, >+ detach_client: &tas_detach_client, >+ command: NULL, >+ inc_use: NULL, >+ dec_use: NULL >+}; >+ >+struct tas_driver_hooks_t *driver_hooks; >+ >+int >+tas_register_driver(struct tas_driver_hooks_t *hooks) >+{ >+ driver_hooks = hooks; >+ return 0; >+} >+ >+int >+tas_get_mixer_level(int mixer, uint *level) >+{ >+ CALL(get_mixer_level,mixer,level); >+} >+ >+int >+tas_set_mixer_level(int mixer,uint level) >+{ >+ CALL(set_mixer_level,mixer,level); >+} >+ >+int >+tas_enter_sleep(void) >+{ >+ CALL0(enter_sleep); >+} >+ >+int >+tas_leave_sleep(void) >+{ >+ CALL0(leave_sleep); >+} >+ >+int >+tas_supported_mixers(void) >+{ >+ CALL0(supported_mixers); >+} >+ >+int >+tas_mixer_is_stereo(int mixer) >+{ >+ CALL(mixer_is_stereo,mixer); >+} >+ >+int >+tas_stereo_mixers(void) >+{ >+ CALL0(stereo_mixers); >+} >+ >+int >+tas_output_device_change(int device_id,int layout_id,int speaker_id) >+{ >+ CALL(output_device_change,device_id,layout_id,speaker_id); >+} >+ >+int >+tas_device_ioctl(u_int cmd, u_long arg) >+{ >+ CALL(device_ioctl,cmd,arg); >+} >+ >+int >+tas_post_init(void) >+{ >+ CALL0(post_init); >+} >+ >+static int >+tas_detect_client(struct i2c_adapter *adapter, int address) >+{ >+ int rc = 0; >+ struct i2c_client *new_client; >+ struct tas_data_t *data; >+ const char *client_name = "tas Digital Equalizer"; >+ >+ if (driver_hooks == NULL) { >+ printk(KERN_ERR "tas_detect_client called with no hooks !\n"); >+ return -ENODEV; >+ } >+ >+ new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); >+ if (!new_client) { >+ rc = -ENOMEM; >+ goto bail; >+ } >+ >+ new_client->data = NULL; >+ >+ new_client->addr = address; >+ new_client->data = data; >+ new_client->adapter = adapter; >+ new_client->driver = &tas_driver; >+ new_client->flags = 0; >+ >+ strcpy(new_client->name,client_name); >+ >+ new_client->id = 0; /* Only one instance supported */ >+ >+ if (driver_hooks->init && driver_hooks->init(new_client)) { >+ rc = -ENODEV; >+ goto bail; >+ } >+ >+ /* Tell the i2c layer a new client has arrived */ >+ if (i2c_attach_client(new_client)) { >+ if (driver_hooks->uninit) >+ driver_hooks->uninit((struct tas_data_t *)new_client->data); >+ rc = -ENODEV; >+ goto bail; >+ } >+ >+ tas_client = new_client; >+bail: >+ if (rc && new_client) { >+ tas_client = NULL; >+ kfree(new_client); >+ } >+ return rc; >+} >+ >+static int >+tas_attach_adapter(struct i2c_adapter *adapter) >+{ >+ if (!strncmp(adapter->name, "mac-io", 6)) >+ return tas_detect_client(adapter, tas_i2c_address); >+ return 0; >+} >+ >+static int >+tas_detach_client(struct i2c_client *client) >+{ >+ if (client == tas_client) { >+ driver_hooks->uninit((struct tas_data_t *)client->data); >+ >+ i2c_detach_client(client); >+ kfree(client); >+ } >+ return 0; >+} >+ >+int __init >+tas_cleanup(void) >+{ >+ if (!tas_initialized) >+ return -ENODEV; >+ i2c_del_driver(&tas_driver); >+ tas_initialized = 0; >+ >+ return 0; >+} >+ >+int __init >+tas_init(int driver_id, const char *driver_name) >+{ >+ int rc; >+ u32* paddr; >+ >+ if (tas_initialized) >+ return 0; >+ >+ strncpy(tas_driver.name,driver_name,31); >+ tas_driver.name[31]=0; >+ tas_driver.id=driver_id; >+ >+ tas_node = find_devices("deq"); >+ if (tas_node == NULL) >+ return -ENODEV; >+ >+ printk(KERN_INFO "tas driver [%s])\n",tas_driver.name); >+ paddr = (u32 *)get_property(tas_node, "i2c-address", NULL); >+ if (paddr) { >+ tas_i2c_address = (*paddr) >> 1; >+ printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", >+ tas_i2c_address); >+ } else >+ printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address); >+ >+ if ((rc = i2c_add_driver(&tas_driver))) { >+ printk("tas: Driver registration failed, module not inserted.\n"); >+ tas_cleanup(); >+ return rc; >+ } >+ tas_initialized = 1; >+ return 0; >+} >+/* >+ * Local Variables: >+ * tab-width: 8 >+ * indent-tabs-mode: t >+ * c-basic-offset: 8 >+ * End: >+ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_common.h linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_common.h >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_common.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_common.h 2003-08-25 23:38:00.000000000 +0200 >@@ -0,0 +1,284 @@ >+#ifndef _TAS_COMMON_H_ >+#define _TAS_COMMON_H_ >+ >+#include <linux/i2c.h> >+#include <linux/soundcard.h> >+#include <asm/string.h> >+ >+#define I2C_DRIVERID_TAS_BASE (0xFEBA) >+ >+#define SET_4_20(shadow, offset, val) \ >+ do { \ >+ (shadow)[(offset)+0] = ((val) >> 16) & 0xff; \ >+ (shadow)[(offset)+1] = ((val) >> 8) & 0xff; \ >+ (shadow)[(offset)+2] = ((val) >> 0) & 0xff; \ >+ } while (0) >+ >+#define GET_4_20(shadow, offset) \ >+ (((u_int)((shadow)[(offset)+0]) << 16) | \ >+ ((u_int)((shadow)[(offset)+1]) << 8) | \ >+ ((u_int)((shadow)[(offset)+2]) << 0)) >+ >+ >+#define TAS_BIQUAD_FAST_LOAD 0x01 >+ >+#define TAS_DRCE_ENABLE 0x01 >+#define TAS_DRCE_ABOVE_RATIO 0x02 >+#define TAS_DRCE_BELOW_RATIO 0x04 >+#define TAS_DRCE_THRESHOLD 0x08 >+#define TAS_DRCE_ENERGY 0x10 >+#define TAS_DRCE_ATTACK 0x20 >+#define TAS_DRCE_DECAY 0x40 >+ >+#define TAS_DRCE_ALL 0x7f >+ >+ >+#define TAS_OUTPUT_HEADPHONES 0x00 >+#define TAS_OUTPUT_INTERNAL_SPKR 0x01 >+#define TAS_OUTPUT_EXTERNAL_SPKR 0x02 >+ >+ >+union tas_biquad_t { >+ struct { >+ int b0,b1,b2,a1,a2; >+ } coeff; >+ int buf[5]; >+}; >+ >+struct tas_biquad_ctrl_t { >+ u_int channel:4; >+ u_int filter:4; >+ >+ union tas_biquad_t data; >+}; >+ >+struct tas_biquad_ctrl_list_t { >+ int flags; >+ int filter_count; >+ struct tas_biquad_ctrl_t biquads[0]; >+}; >+ >+struct tas_ratio_t { >+ unsigned short val; /* 8.8 */ >+ unsigned short expand; /* 0 = compress, !0 = expand. */ >+}; >+ >+struct tas_drce_t { >+ unsigned short enable; >+ struct tas_ratio_t above; >+ struct tas_ratio_t below; >+ short threshold; /* dB, 8.8 signed */ >+ unsigned short energy; /* seconds, 4.12 unsigned */ >+ unsigned short attack; /* seconds, 4.12 unsigned */ >+ unsigned short decay; /* seconds, 4.12 unsigned */ >+}; >+ >+struct tas_drce_ctrl_t { >+ uint flags; >+ >+ struct tas_drce_t data; >+}; >+ >+struct tas_gain_t >+{ >+ unsigned int *master; >+ unsigned int *treble; >+ unsigned int *bass; >+ unsigned int *mixer; >+}; >+ >+typedef char tas_shadow_t[16]; >+ >+struct tas_data_t >+{ >+ struct i2c_client *client; >+ tas_shadow_t *shadow; >+ uint mixer[SOUND_MIXER_NRDEVICES]; >+}; >+ >+typedef int (*tas_hook_init_t)(struct i2c_client *); >+typedef int (*tas_hook_post_init_t)(struct tas_data_t *); >+typedef void (*tas_hook_uninit_t)(struct tas_data_t *); >+ >+typedef int (*tas_hook_get_mixer_level_t)(struct tas_data_t *,int,uint *); >+typedef int (*tas_hook_set_mixer_level_t)(struct tas_data_t *,int,uint); >+ >+typedef int (*tas_hook_enter_sleep_t)(struct tas_data_t *); >+typedef int (*tas_hook_leave_sleep_t)(struct tas_data_t *); >+ >+typedef int (*tas_hook_supported_mixers_t)(struct tas_data_t *); >+typedef int (*tas_hook_mixer_is_stereo_t)(struct tas_data_t *,int); >+typedef int (*tas_hook_stereo_mixers_t)(struct tas_data_t *); >+ >+typedef int (*tas_hook_output_device_change_t)(struct tas_data_t *,int,int,int); >+typedef int (*tas_hook_device_ioctl_t)(struct tas_data_t *,u_int,u_long); >+ >+struct tas_driver_hooks_t { >+ /* >+ * All hardware initialisation must be performed in >+ * post_init(), as tas_dmasound_init() does a hardware reset. >+ * >+ * init() is called before tas_dmasound_init() so that >+ * ouput_device_change() is always called after i2c driver >+ * initialisation. The implication is that >+ * output_device_change() must cope with the fact that it >+ * may be called before post_init(). >+ */ >+ >+ tas_hook_init_t init; >+ tas_hook_post_init_t post_init; >+ tas_hook_uninit_t uninit; >+ >+ tas_hook_get_mixer_level_t get_mixer_level; >+ tas_hook_set_mixer_level_t set_mixer_level; >+ >+ tas_hook_enter_sleep_t enter_sleep; >+ tas_hook_leave_sleep_t leave_sleep; >+ >+ tas_hook_supported_mixers_t supported_mixers; >+ tas_hook_mixer_is_stereo_t mixer_is_stereo; >+ tas_hook_stereo_mixers_t stereo_mixers; >+ >+ tas_hook_output_device_change_t output_device_change; >+ tas_hook_device_ioctl_t device_ioctl; >+}; >+ >+enum tas_write_mode_t { >+ WRITE_HW = 0x01, >+ WRITE_SHADOW = 0x02, >+ WRITE_NORMAL = 0x03, >+ FORCE_WRITE = 0x04 >+}; >+ >+static inline uint >+tas_mono_to_stereo(uint mono) >+{ >+ mono &=0xff; >+ return mono | (mono<<8); >+} >+ >+/* >+ * Todo: make these functions a bit more efficient ! >+ */ >+static inline int >+tas_write_register( struct tas_data_t *self, >+ uint reg_num, >+ uint reg_width, >+ char *data, >+ uint write_mode) >+{ >+ int rc; >+ >+ if (reg_width==0 || data==NULL || self==NULL) >+ return -EINVAL; >+ if (!(write_mode & FORCE_WRITE) && >+ !memcmp(data,self->shadow[reg_num],reg_width)) >+ return 0; >+ >+ if (write_mode & WRITE_SHADOW) >+ memcpy(self->shadow[reg_num],data,reg_width); >+ if (write_mode & WRITE_HW) { >+ rc=i2c_smbus_write_block_data(self->client, >+ reg_num, >+ reg_width, >+ data); >+ if (rc < 0) { >+ printk("tas: I2C block write failed \n"); >+ return rc; >+ } >+ } >+ return 0; >+} >+ >+static inline int >+tas_sync_register( struct tas_data_t *self, >+ uint reg_num, >+ uint reg_width) >+{ >+ int rc; >+ >+ if (reg_width==0 || self==NULL) >+ return -EINVAL; >+ rc=i2c_smbus_write_block_data(self->client, >+ reg_num, >+ reg_width, >+ self->shadow[reg_num]); >+ if (rc < 0) { >+ printk("tas: I2C block write failed \n"); >+ return rc; >+ } >+ return 0; >+} >+ >+static inline int >+tas_write_byte_register( struct tas_data_t *self, >+ uint reg_num, >+ char data, >+ uint write_mode) >+{ >+ if (self==NULL) >+ return -1; >+ if (!(write_mode & FORCE_WRITE) && data != self->shadow[reg_num][0]) >+ return 0; >+ if (write_mode & WRITE_SHADOW) >+ self->shadow[reg_num][0]=data; >+ if (write_mode & WRITE_HW) { >+ if (i2c_smbus_write_byte_data(self->client, reg_num, data) < 0) { >+ printk("tas: I2C byte write failed \n"); >+ return -1; >+ } >+ } >+ return 0; >+} >+ >+static inline int >+tas_sync_byte_register( struct tas_data_t *self, >+ uint reg_num, >+ uint reg_width) >+{ >+ if (reg_width==0 || self==NULL) >+ return -1; >+ if (i2c_smbus_write_byte_data( >+ self->client, reg_num, self->shadow[reg_num][0]) < 0) { >+ printk("tas: I2C byte write failed \n"); >+ return -1; >+ } >+ return 0; >+} >+ >+static inline int >+tas_read_register( struct tas_data_t *self, >+ uint reg_num, >+ uint reg_width, >+ char *data) >+{ >+ if (reg_width==0 || data==NULL || self==NULL) >+ return -1; >+ memcpy(data,self->shadow[reg_num],reg_width); >+ return 0; >+} >+ >+extern int tas_register_driver(struct tas_driver_hooks_t *hooks); >+ >+extern int tas_get_mixer_level(int mixer,uint *level); >+extern int tas_set_mixer_level(int mixer,uint level); >+extern int tas_enter_sleep(void); >+extern int tas_leave_sleep(void); >+extern int tas_supported_mixers(void); >+extern int tas_mixer_is_stereo(int mixer); >+extern int tas_stereo_mixers(void); >+extern int tas_output_device_change(int,int,int); >+extern int tas_device_ioctl(u_int, u_long); >+ >+extern int tas_cleanup(void); >+extern int tas_init(int driver_id,const char *driver_name); >+extern int tas_post_init(void); >+ >+#endif /* _TAS_COMMON_H_ */ >+/* >+ * Local Variables: >+ * tab-width: 8 >+ * indent-tabs-mode: t >+ * c-basic-offset: 8 >+ * End: >+ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_eq_prefs.h linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_eq_prefs.h >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_eq_prefs.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_eq_prefs.h 2003-08-25 23:37:37.000000000 +0200 >@@ -0,0 +1,24 @@ >+#ifndef _TAS_EQ_PREFS_H_ >+#define _TAS_EQ_PREFS_H_ >+ >+struct tas_eq_pref_t { >+ u_int sample_rate; >+ u_int device_id; >+ u_int output_id; >+ u_int speaker_id; >+ >+ struct tas_drce_t *drce; >+ >+ u_int filter_count; >+ struct tas_biquad_ctrl_t *biquads; >+}; >+ >+#endif /* _TAS_EQ_PREFS_H_ */ >+ >+/* >+ * Local Variables: >+ * tab-width: 8 >+ * indent-tabs-mode: t >+ * c-basic-offset: 8 >+ * End: >+ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_ioctl.h linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_ioctl.h >--- linux-2.4.22-ppc-dev.orig/drivers/sound/dmasound/tas_ioctl.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/sound/dmasound/tas_ioctl.h 2003-08-25 23:37:39.000000000 +0200 >@@ -0,0 +1,24 @@ >+#ifndef _TAS_IOCTL_H_ >+#define _TAS_IOCTL_H_ >+ >+#include <linux/i2c.h> >+#include <linux/soundcard.h> >+ >+ >+#define TAS_READ_EQ _SIOR('t',0,struct tas_biquad_ctrl_t) >+#define TAS_WRITE_EQ _SIOW('t',0,struct tas_biquad_ctrl_t) >+ >+#define TAS_READ_EQ_LIST _SIOR('t',1,struct tas_biquad_ctrl_t) >+#define TAS_WRITE_EQ_LIST _SIOW('t',1,struct tas_biquad_ctrl_t) >+ >+#define TAS_READ_EQ_FILTER_COUNT _SIOR('t',2,int) >+#define TAS_READ_EQ_CHANNEL_COUNT _SIOR('t',3,int) >+ >+#define TAS_READ_DRCE _SIOR('t',4,struct tas_drce_ctrl_t) >+#define TAS_WRITE_DRCE _SIOW('t',4,struct tas_drce_ctrl_t) >+ >+#define TAS_READ_DRCE_CAPS _SIOR('t',5,int) >+#define TAS_READ_DRCE_MIN _SIOR('t',6,int) >+#define TAS_READ_DRCE_MAX _SIOR('t',7,int) >+ >+#endif >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/usb/host/usb-ohci.c linux-2.4.22-ppc-dev/drivers/usb/host/usb-ohci.c >--- linux-2.4.22-ppc-dev.orig/drivers/usb/host/usb-ohci.c 2003-08-27 15:18:01.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/usb/host/usb-ohci.c 2003-08-25 23:38:03.000000000 +0200 >@@ -714,8 +714,10 @@ > list_add (&urb->urb_list, entry); > > /* drive timeouts by SF (messy, but works) */ >- writel (OHCI_INTR_SF, &ohci->regs->intrenable); >- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ >+ if (!ohci->sleeping) { >+ writel (OHCI_INTR_SF, &ohci->regs->intrenable); >+ (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ >+ } > } > #endif > >@@ -1010,6 +1012,7 @@ > case PIPE_CONTROL: > ed->hwNextED = 0; > if (ohci->ed_controltail == NULL) { >+ io_barrier(); > writel (ed->dma, &ohci->regs->ed_controlhead); > } else { > ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma); >@@ -1018,6 +1021,7 @@ > if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && > !ohci->ed_rm_list[1] && !ohci->sleeping) { > ohci->hc_control |= OHCI_CTRL_CLE; >+ io_barrier(); > writel (ohci->hc_control, &ohci->regs->control); > } > ohci->ed_controltail = edi; >@@ -1026,6 +1030,7 @@ > case PIPE_BULK: > ed->hwNextED = 0; > if (ohci->ed_bulktail == NULL) { >+ io_barrier(); > writel (ed->dma, &ohci->regs->ed_bulkhead); > } else { > ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma); >@@ -1034,6 +1039,7 @@ > if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && > !ohci->ed_rm_list[1] && !ohci->sleeping) { > ohci->hc_control |= OHCI_CTRL_BLE; >+ io_barrier(); > writel (ohci->hc_control, &ohci->regs->control); > } > ohci->ed_bulktail = edi; >@@ -1126,7 +1132,8 @@ > if (ed->ed_prev == NULL) { > if (!ed->hwNextED) { > ohci->hc_control &= ~OHCI_CTRL_CLE; >- writel (ohci->hc_control, &ohci->regs->control); >+ if (!ohci->sleeping) >+ writel (ohci->hc_control, &ohci->regs->control); > } > writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead); > } else { >@@ -1143,7 +1150,8 @@ > if (ed->ed_prev == NULL) { > if (!ed->hwNextED) { > ohci->hc_control &= ~OHCI_CTRL_BLE; >- writel (ohci->hc_control, &ohci->regs->control); >+ if (!ohci->sleeping) >+ writel (ohci->hc_control, &ohci->regs->control); > } > writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead); > } else { >@@ -1272,16 +1280,19 @@ > return; > > ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP); >+ io_barrier(); > > if (!ohci->disabled) { > switch (ed->type) { > case PIPE_CONTROL: /* stop control list */ > ohci->hc_control &= ~OHCI_CTRL_CLE; >- writel (ohci->hc_control, &ohci->regs->control); >+ if (!ohci->sleeping) >+ writel (ohci->hc_control, &ohci->regs->control); > break; > case PIPE_BULK: /* stop bulk list */ > ohci->hc_control &= ~OHCI_CTRL_BLE; >- writel (ohci->hc_control, &ohci->regs->control); >+ if (!ohci->sleeping) >+ writel (ohci->hc_control, &ohci->regs->control); > break; > } > } >@@ -1413,7 +1424,7 @@ > } > > if (!ohci->sleeping) { >- wmb(); >+ io_barrier(); > writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ > (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ > } >@@ -1442,7 +1453,7 @@ > TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; > td_fill (ohci, info, data, 0, urb, cnt++); > if (!ohci->sleeping) { >- wmb(); >+ io_barrier(); > writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ > (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ > } >@@ -1550,6 +1561,7 @@ > > td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0; > ohci->hcca->done_head = 0; >+ wmb(); > > while (td_list_hc) { > td_list = dma_to_td (ohci, td_list_hc); >@@ -1658,6 +1670,7 @@ > > /* maybe reenable control and bulk lists */ > if (!ohci->disabled) { >+ io_barrier(); > if (ctrl) /* reset control list */ > writel (0, &ohci->regs->ed_controlcurrent); > if (bulk) /* reset bulk list */ >@@ -2318,6 +2331,10 @@ > struct ohci_regs * regs = ohci->regs; > int ints; > >+ /* Sanity check */ >+ if (ohci->sleeping) >+ return; >+ > /* avoid (slow) readl if only WDH happened */ > if ((ohci->hcca->done_head != 0) > && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { >@@ -2624,6 +2641,16 @@ > if (pci_enable_device(dev) < 0) > return -ENODEV; > >+#ifdef CONFIG_PMAC_PBOOK >+ { >+ struct device_node *of_node; >+ >+ /* Re-enable USB PAD & cell clock */ >+ of_node = pci_device_to_OF_node (dev); >+ if (of_node) >+ pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); >+ } >+#endif > if (!dev->irq) { > err("found OHCI device with no IRQ assigned. check BIOS settings!"); > pci_disable_device (dev); >@@ -2719,6 +2746,12 @@ > info ("USB suspend: usb-%s", dev->slot_name); > ohci->sleeping = 1; > >+#ifdef CONFIG_PMAC_PBOOK >+ if (_machine == _MACH_Pmac) >+ disable_irq (ohci->irq); >+ /* else, 2.4 assumes shared irqs -- don't disable */ >+#endif >+ > /* First stop processing */ > spin_lock_irqsave (&usb_ed_lock, flags); > ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); >@@ -2732,11 +2765,6 @@ > if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) > mdelay (1); > >-#ifdef CONFIG_PMAC_PBOOK >- if (_machine == _MACH_Pmac) >- disable_irq (ohci->irq); >- /* else, 2.4 assumes shared irqs -- don't disable */ >-#endif > /* Enable remote wakeup */ > writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable); > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/usb/host/usb-ohci.h linux-2.4.22-ppc-dev/drivers/usb/host/usb-ohci.h >--- linux-2.4.22-ppc-dev.orig/drivers/usb/host/usb-ohci.h 2003-06-13 16:51:36.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/usb/host/usb-ohci.h 2003-08-25 23:37:39.000000000 +0200 >@@ -58,7 +58,7 @@ > > dma_addr_t dma; > __u32 unused[3]; >-} __attribute((aligned(16))); >+} __attribute((aligned(32))); > typedef struct ed ed_t; > > >@@ -567,7 +567,7 @@ > return -ENOMEM; > ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev, > sizeof (struct ohci_device), >- 16 /* byte alignment */, >+ 32 /* byte alignment */, > 0 /* no page-crossing issues */, > GFP_KERNEL | OHCI_MEM_FLAGS); > if (!ohci->dev_cache) >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/usb/storage/scsiglue.c linux-2.4.22-ppc-dev/drivers/usb/storage/scsiglue.c >--- linux-2.4.22-ppc-dev.orig/drivers/usb/storage/scsiglue.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/usb/storage/scsiglue.c 2003-08-25 23:37:28.000000000 +0200 >@@ -75,16 +75,19 @@ > { > struct us_data *us; > char local_name[32]; >- /* Note: this function gets called with io_request_lock spinlock helt! */ >+ spin_unlock_irq(&io_request_lock); >+ > /* This is not nice at all, but how else are we to get the > * data here? */ > us = (struct us_data *)sht->proc_dir; > > /* set up the name of our subdirectory under /proc/scsi/ */ > sprintf(local_name, "usb-storage-%d", us->host_number); >- sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC); >- if (!sht->proc_name) >+ sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL); >+ if (!sht->proc_name) { >+ spin_lock_irq(&io_request_lock); > return 0; >+ } > strcpy(sht->proc_name, local_name); > > /* we start with no /proc directory entry */ >@@ -95,12 +98,14 @@ > if (us->host) { > us->host->hostdata[0] = (unsigned long)us; > us->host_no = us->host->host_no; >+ spin_lock_irq(&io_request_lock); > return 1; > } > > /* odd... didn't register properly. Abort and free pointers */ > kfree(sht->proc_name); > sht->proc_name = NULL; >+ spin_lock_irq(&io_request_lock); > return 0; > } > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/Config.in linux-2.4.22-ppc-dev/drivers/video/Config.in >--- linux-2.4.22-ppc-dev.orig/drivers/video/Config.in 2003-08-27 15:18:01.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/Config.in 2003-08-25 23:37:27.000000000 +0200 >@@ -73,7 +73,7 @@ > dep_bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE $CONFIG_ALL_PPC > bool ' Chips 65550 display support' CONFIG_FB_CT65550 > bool ' IMS Twin Turbo display support' CONFIG_FB_IMSTT >- bool ' S3 Trio display support' CONFIG_FB_S3TRIO >+ dep_bool ' S3 Trio display support' CONFIG_FB_S3TRIO $CONFIG_ALL_PPC > tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16 > fi > if [ "$CONFIG_PARISC" = "y" ]; then >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/aty/atyfb.h linux-2.4.22-ppc-dev/drivers/video/aty/atyfb.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/aty/atyfb.h 2002-11-29 00:53:15.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/video/aty/atyfb.h 2003-08-25 23:37:43.000000000 +0200 >@@ -124,6 +124,7 @@ > #endif > } fbcon_cmap; > u8 blitter_may_be_busy; >+ int asleep; > #ifdef __sparc__ > u8 mmaped; > int open; >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/aty/atyfb_base.c linux-2.4.22-ppc-dev/drivers/video/aty/atyfb_base.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/aty/atyfb_base.c 2002-11-29 00:53:15.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/video/aty/atyfb_base.c 2003-08-25 23:37:34.000000000 +0200 >@@ -748,6 +748,8 @@ > > info->current_par = *par; > >+ if (info->asleep) >+ return; > if (info->blitter_may_be_busy) > wait_for_idle(info); > tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); >@@ -1192,6 +1194,10 @@ > return -EINVAL; > par->crtc.xoffset = xoffset; > par->crtc.yoffset = yoffset; >+ >+ if (info->asleep) >+ return 0; >+ > set_off_pitch(par, info); > return 0; > } >@@ -1660,6 +1666,7 @@ > } > break; > case PBOOK_SLEEP_NOW: >+ acquire_console_sem(); > if (currcon >= 0) > fb_display[currcon].dispsw = &fbcon_dummy; > if (info->blitter_may_be_busy) >@@ -1675,11 +1682,14 @@ > > /* Blank display and LCD */ > atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); >+ info->asleep = 1; > > /* Set chip to "suspend" mode */ > result = aty_power_mgmt(1, info); >+ release_console_sem(); > break; > case PBOOK_WAKE: >+ acquire_console_sem(); > /* Wakeup chip */ > result = aty_power_mgmt(0, info); > >@@ -1690,6 +1700,7 @@ > vfree(info->save_framebuffer); > info->save_framebuffer = 0; > } >+ info->asleep = 0; > /* Restore display */ > if (currcon >= 0) { > atyfb_set_dispsw(&fb_display[currcon], >@@ -1697,6 +1708,11 @@ > info->current_par.accel_flags & FB_ACCELF_TEXT); > } > atyfbcon_blank(0, (struct fb_info *)info); >+ /* XXX We may want to re-call atyfb_set_par and make >+ * sure panning & cursor & palette are correct as we >+ * skipped any change to these during suspend. >+ */ >+ release_console_sem(); > break; > } > } >@@ -2720,6 +2736,9 @@ > struct fb_info_aty *info = (struct fb_info_aty *)fb; > u8 gen_cntl; > >+ if (info->asleep) >+ return; >+ > #ifdef CONFIG_PMAC_BACKLIGHT > if ((_machine == _MACH_Pmac) && blank) > set_backlight_enable(0); >@@ -2792,23 +2811,25 @@ > info->palette[regno].red = red; > info->palette[regno].green = green; > info->palette[regno].blue = blue; >- i = aty_ld_8(DAC_CNTL, info) & 0xfc; >- if (M64_HAS(EXTRA_BRIGHT)) >- i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ >- aty_st_8(DAC_CNTL, i, info); >- aty_st_8(DAC_MASK, 0xff, info); >- scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; >+ if (!info->asleep) { >+ i = aty_ld_8(DAC_CNTL, info) & 0xfc; >+ if (M64_HAS(EXTRA_BRIGHT)) >+ i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ >+ aty_st_8(DAC_CNTL, i, info); >+ aty_st_8(DAC_MASK, 0xff, info); >+ scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; > #ifdef CONFIG_ATARI >- out_8(&info->aty_cmap_regs->windex, regno << scale); >- out_8(&info->aty_cmap_regs->lut, red); >- out_8(&info->aty_cmap_regs->lut, green); >- out_8(&info->aty_cmap_regs->lut, blue); >+ out_8(&info->aty_cmap_regs->windex, regno << scale); >+ out_8(&info->aty_cmap_regs->lut, red); >+ out_8(&info->aty_cmap_regs->lut, green); >+ out_8(&info->aty_cmap_regs->lut, blue); > #else >- writeb(regno << scale, &info->aty_cmap_regs->windex); >- writeb(red, &info->aty_cmap_regs->lut); >- writeb(green, &info->aty_cmap_regs->lut); >- writeb(blue, &info->aty_cmap_regs->lut); >+ writeb(regno << scale, &info->aty_cmap_regs->windex); >+ writeb(red, &info->aty_cmap_regs->lut); >+ writeb(green, &info->aty_cmap_regs->lut); >+ writeb(blue, &info->aty_cmap_regs->lut); > #endif >+ } > if (regno < 16) > switch (info->current_par.crtc.bpp) { > #ifdef FBCON_HAS_CFB16 >@@ -2859,6 +2880,9 @@ > struct vc_data *conp = p->conp; > u32 yres, yoffset, sy, height; > >+ if (info->asleep) >+ return 0; >+ > yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; > yoffset = fb_display[con].var.yoffset; > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/aty/mach64_cursor.c linux-2.4.22-ppc-dev/drivers/video/aty/mach64_cursor.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/aty/mach64_cursor.c 2001-10-25 22:53:52.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/aty/mach64_cursor.c 2003-08-25 23:37:39.000000000 +0200 >@@ -54,7 +54,7 @@ > const u8 *blue = cursor_color_map; > int i; > >- if (!c) >+ if (!c || fb->asleep) > return; > > #ifdef __sparc__ >@@ -81,7 +81,7 @@ > u8 *ram, m, b; > int x, y; > >- if (!c) >+ if (!c || fb->asleep) > return; > > #ifdef __sparc__ >@@ -118,7 +118,7 @@ > u16 xoff, yoff; > int x, y; > >- if (!c) >+ if (!c || fb->asleep) > return; > > #ifdef __sparc__ >@@ -297,8 +297,10 @@ > c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j)); > } > >- aty_set_cursor_color(fb); >- aty_set_cursor_shape(fb); >+ if (!fb->asleep) { >+ aty_set_cursor_color(fb); >+ aty_set_cursor_shape(fb); >+ } > } > return 1; > } >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/aty128fb.c linux-2.4.22-ppc-dev/drivers/video/aty128fb.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/aty128fb.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/aty128fb.c 2003-08-25 23:37:35.000000000 +0200 >@@ -55,7 +55,7 @@ > #include <linux/ioport.h> > #include <asm/io.h> > >-#ifdef CONFIG_PPC >+#ifdef CONFIG_ALL_PPC > #include <asm/prom.h> > #include <asm/pci-bridge.h> > #include <video/macmodes.h> >@@ -101,7 +101,7 @@ > #define DBG(fmt, args...) > #endif > >-#ifndef CONFIG_PPC >+#ifndef CONFIG_ALL_PPC > /* default mode */ > static struct fb_var_screeninfo default_var __initdata = { > /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ >@@ -111,7 +111,7 @@ > 0, FB_VMODE_NONINTERLACED > }; > >-#else /* CONFIG_PPC */ >+#else /* CONFIG_ALL_PPC */ > /* default to 1024x768 at 75Hz on PPC - this will work > * on the iMac, the usual 640x480 @ 60Hz doesn't. */ > static struct fb_var_screeninfo default_var = { >@@ -121,7 +121,7 @@ > 0, 0, -1, -1, 0, 12699, 160, 32, 28, 1, 96, 3, > FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED > }; >-#endif /* CONFIG_PPC */ >+#endif /* CONFIG_ALL_PPC */ > > /* default modedb mode */ > /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ >@@ -171,7 +171,7 @@ > }; > > /* packed BIOS settings */ >-#ifndef CONFIG_PPC >+#ifndef CONFIG_ALL_PPC > typedef struct { > u8 clock_chip_type; > u8 struct_size; >@@ -196,7 +196,7 @@ > u32 XCLK_min_freq; > u32 XCLK_max_freq; > } __attribute__ ((packed)) PLL_BLOCK; >-#endif /* !CONFIG_PPC */ >+#endif /* !CONFIG_ALL_PPC */ > > /* onboard memory information */ > struct aty128_meminfo { >@@ -233,7 +233,7 @@ > > static char *mode_option __initdata = NULL; > >-#ifdef CONFIG_PPC >+#ifdef CONFIG_ALL_PPC > static int default_vmode __initdata = VMODE_1024_768_60; > static int default_cmode __initdata = CMODE_8; > #endif >@@ -397,7 +397,7 @@ > const struct aty128_chip_info *aci); > static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128 > *board_list, struct fb_info_aty128 *new_node); >-#if !defined(CONFIG_PPC) && !defined(__sparc__) >+#if !defined(CONFIG_ALL_PPC) && !defined(__sparc__) > static void __init aty128_get_pllinfo(struct fb_info_aty128 *info, > char *bios_seg); > static char __init *aty128find_ROM(struct fb_info_aty128 *info); >@@ -1778,7 +1778,7 @@ > mtrr = 0; > } > #endif >-#ifdef CONFIG_PPC >+#ifdef CONFIG_ALL_PPC > /* vmode and cmode depreciated */ > else if (!strncmp(this_opt, "vmode:", 6)) { > unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); >@@ -1801,7 +1801,7 @@ > break; > } > } >-#endif /* CONFIG_PPC */ >+#endif /* CONFIG_ALL_PPC */ > else > mode_option = this_opt; > } >@@ -1858,7 +1858,7 @@ > #endif > > var = default_var; >-#ifdef CONFIG_PPC >+#ifdef CONFIG_ALL_PPC > if (_machine == _MACH_Pmac) { > if (mode_option) { > if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) >@@ -1897,7 +1897,7 @@ > var = default_var; > } > } else >-#endif /* CONFIG_PPC */ >+#endif /* CONFIG_ALL_PPC */ > { > if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, > &defaultmode, 8) == 0) >@@ -2011,7 +2011,7 @@ > struct fb_info_aty128 *info = NULL; > unsigned long fb_addr, reg_addr; > int err; >-#if !defined(CONFIG_PPC) && !defined(__sparc__) >+#if !defined(CONFIG_ALL_PPC) && !defined(__sparc__) > char *bios_seg = NULL; > #endif > >@@ -2074,7 +2074,7 @@ > goto err_out; > } > >-#if !defined(CONFIG_PPC) && !defined(__sparc__) >+#if !defined(CONFIG_ALL_PPC) && !defined(__sparc__) > if (!(bios_seg = aty128find_ROM(info))) > printk(KERN_INFO "aty128fb: Rage128 BIOS not located. " > "Guessing...\n"); >@@ -2126,7 +2126,7 @@ > > > /* PPC and Sparc cannot read video ROM */ >-#if !defined(CONFIG_PPC) && !defined(__sparc__) >+#if !defined(CONFIG_ALL_PPC) && !defined(__sparc__) > static char __init > *aty128find_ROM(struct fb_info_aty128 *info) > { >@@ -2218,14 +2218,14 @@ > info->constants.dotclock); > > } >-#endif /* !CONFIG_PPC */ >+#endif /* !CONFIG_ALL_PPC */ > > > /* fill in known card constants if pll_block is not available */ > static void __init > aty128_timings(struct fb_info_aty128 *info) > { >-#ifdef CONFIG_PPC >+#ifdef CONFIG_ALL_PPC > /* instead of a table lookup, assume OF has properly > * setup the PLL registers and use their values > * to set the XCLK values and reference divider values */ >@@ -2240,7 +2240,7 @@ > if (!info->constants.dotclock) > info->constants.dotclock = 2950; > >-#ifdef CONFIG_PPC >+#ifdef CONFIG_ALL_PPC > x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); > xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; > Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; >@@ -2468,9 +2468,9 @@ > #define ATY_MIRROR_CRT_ON 0x00000002 > > /* out param: u32* backlight value: 0 to 15 */ >-#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, sizeof(__u32*)) >+#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32) > /* in param: u32* backlight value: 0 to 15 */ >-#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, sizeof(__u32*)) >+#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32) > > static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, > u_long arg, int con, struct fb_info *info) >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/offb.c linux-2.4.22-ppc-dev/drivers/video/offb.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/offb.c 2002-02-25 20:38:07.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/video/offb.c 2003-08-25 23:37:36.000000000 +0200 >@@ -448,6 +448,10 @@ > unsigned long regbase = dp->addrs[1].address; > info->cmap_adr = ioremap(regbase, 0x1FFF); > info->cmap_type = cmap_radeon; >+ } else if (dp && !strncmp(name, "ATY,BlueStar", 12)) { >+ unsigned long regbase = dp->addrs[2].address; >+ info->cmap_adr = ioremap(regbase, 0x1FFF); >+ info->cmap_type = cmap_radeon; > } else if (!strncmp(name, "ATY,", 4)) { > /* Hrm... this is bad... any recent ATI not covered > * by the previous cases will get there, while this >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/radeon.h linux-2.4.22-ppc-dev/drivers/video/radeon.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/radeon.h 2003-08-27 15:18:01.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/radeon.h 2003-08-25 23:37:28.000000000 +0200 >@@ -368,6 +368,8 @@ > #define DST_PITCH_OFFSET 0x142C > #define DEFAULT_PITCH_OFFSET 0x16E0 > #define DEFAULT_SC_BOTTOM_RIGHT 0x16E8 >+#define SRC_PITCH_OFFSET 0x1428 >+#define DST_PITCH_OFFSET 0x142C > #define DP_GUI_MASTER_CNTL 0x146C > #define SC_TOP_LEFT 0x16EC > #define SC_BOTTOM_RIGHT 0x16F0 >@@ -376,6 +378,7 @@ > #define RB2D_DSTCACHE_CTLSTAT 0x342C > #define LVDS_GEN_CNTL 0x02d0 > #define LVDS_PLL_CNTL 0x02d4 >+#define FP2_GEN_CNTL 0x0288 > #define TMDS_CNTL 0x0294 > #define TMDS_CRC 0x02a0 > #define TMDS_TRANSMITTER_CNTL 0x02a4 >@@ -801,6 +804,12 @@ > /* MPLL_CNTL bit constants */ > #define MPLL_RESET 0x00000001 > >+/* MDLL_CKO bit constants */ >+#define MCKOA_SLEEP 0x00000001 >+#define MCKOA_RESET 0x00000002 >+#define MCKOA_REF_SKEW_MASK 0x00000700 >+#define MCKOA_FB_SKEW_MASK 0x00007000 >+ > /* MDLL_RDCKA bit constants */ > #define MRDCKA0_SLEEP 0x00000001 > #define MRDCKA0_RESET 0x00000002 >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/Makefile linux-2.4.22-ppc-dev/drivers/video/riva/Makefile >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/Makefile 2001-02-03 21:48:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/Makefile 2003-08-25 23:37:53.000000000 +0200 >@@ -9,7 +9,7 @@ > > O_TARGET := rivafb.o > >-obj-y := fbdev.o riva_hw.o accel.o >+obj-y := fbdev.o nv_setup.o riva_hw.o accel.o > obj-m := $(O_TARGET) > > include $(TOPDIR)/Rules.make >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/accel.c linux-2.4.22-ppc-dev/drivers/video/riva/accel.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/accel.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/accel.c 2003-08-25 23:37:55.000000000 +0200 >@@ -14,6 +14,7 @@ > > inline void wait_for_idle(struct rivafb_info *rinfo) > { >+ mb(); > while (rinfo->riva.Busy(&rinfo->riva)); > } > >@@ -48,7 +49,9 @@ > > RIVA_FIFO_FREE(rinfo->riva, Bitmap, 2); > rinfo->riva.Bitmap->UnclippedRectangle[0].TopLeft = (sx << 16) | sy; >+ wmb(); > rinfo->riva.Bitmap->UnclippedRectangle[0].WidthHeight = (width << 16) | height; >+ wmb(); > } > > static void fbcon_riva_bmove(struct display *p, int sy, int sx, int dy, int dx, >@@ -66,6 +69,7 @@ > RIVA_FIFO_FREE(rinfo->riva, Blt, 3); > rinfo->riva.Blt->TopLeftSrc = (sy << 16) | sx; > rinfo->riva.Blt->TopLeftDst = (dy << 16) | dx; >+ wmb(); > rinfo->riva.Blt->WidthHeight = (height << 16) | width; > > wait_for_idle(rinfo); >@@ -141,7 +145,9 @@ > rinfo->riva.Bitmap->Color1E = fgx; > rinfo->riva.Bitmap->WidthHeightInE = (h << 16) | 32; > rinfo->riva.Bitmap->WidthHeightOutE = (h << 16) | 32; >+ wmb(); > rinfo->riva.Bitmap->PointE = (yy << 16) | (xx & 0xFFFF); >+ wmb(); > > d = &rinfo->riva.Bitmap->MonochromeData01E; > for (i = h; i > 0; i-=16) { >@@ -151,10 +157,19 @@ > cnt = i; > RIVA_FIFO_FREE(rinfo->riva, Bitmap, cnt); > for (j = 0; j < cnt; j++) { >- if (w <= 8) >+ if (w <= 8) { >+#ifdef __BIG_ENDIAN >+ cdat2 = (*cdat++) << 24; >+#else > cdat2 = *cdat++; >- else >+#endif >+ } else { >+#ifdef __BIG_ENDIAN > cdat2 = *((u16*)cdat)++; >+#else >+ cdat2 = (*((u16*)cdat)++) << 16; >+#endif >+ } > fbcon_reverse_order(&cdat2); > d[j] = cdat2; > } >@@ -228,9 +243,11 @@ > > RIVA_FIFO_FREE(rinfo->riva, Rop, 1); > rinfo->riva.Rop->Rop3 = 0x66; // XOR >+ wmb(); > riva_rectfill(rinfo, yy, xx, fontheight(p), fontwidth(p), 0x0f); > RIVA_FIFO_FREE(rinfo->riva, Rop, 1); > rinfo->riva.Rop->Rop3 = 0xCC; // back to COPY >+ wmb(); > } > > static void fbcon_riva8_clear_margins(struct vc_data *conp, struct display *p, >@@ -243,17 +260,10 @@ > setup: fbcon_riva8_setup, > bmove: fbcon_riva_bmove, > clear: fbcon_riva8_clear, >-#ifdef __BIG_ENDIAN >- putc: fbcon_cfb8_putc, >- putcs: fbcon_cfb8_putcs, >- revc: fbcon_cfb8_revc, >- clear_margins: fbcon_cfb8_clear_margins, >-#else > putc: fbcon_riva8_putc, > putcs: fbcon_riva8_putcs, > revc: fbcon_riva8_revc, > clear_margins: fbcon_riva8_clear_margins, >-#endif > fontwidthmask: FONTWIDTHRANGE(4, 16) > }; > #endif >@@ -268,9 +278,11 @@ > > RIVA_FIFO_FREE(rinfo->riva, Rop, 1); > rinfo->riva.Rop->Rop3 = 0x66; // XOR >+ wmb(); > riva_rectfill(rinfo, yy, xx, fontheight(p), fontwidth(p), 0xffffffff); > RIVA_FIFO_FREE(rinfo->riva, Rop, 1); > rinfo->riva.Rop->Rop3 = 0xCC; // back to COPY >+ wmb(); > } > #endif > >@@ -353,17 +365,10 @@ > setup: fbcon_riva16_setup, > bmove: fbcon_riva_bmove, > clear: fbcon_riva16_clear, >-#ifdef __BIG_ENDIAN >- putc: fbcon_cfb16_putc, >- putcs: fbcon_cfb16_putcs, >- revc: fbcon_cfb16_revc, >- clear_margins: fbcon_cfb16_clear_margins, >-#else > putc: fbcon_riva16_putc, > putcs: fbcon_riva16_putcs, > revc: fbcon_riva1632_revc, > clear_margins: fbcon_riva16_clear_margins, >-#endif > fontwidthmask: FONTWIDTHRANGE(4, 16) > }; > #endif >@@ -434,17 +439,10 @@ > setup: fbcon_riva32_setup, > bmove: fbcon_riva_bmove, > clear: fbcon_riva32_clear, >-#ifdef __BIG_ENDIAN >- putc: fbcon_cfb32_putc, >- putcs: fbcon_cfb32_putcs, >- revc: fbcon_cfb32_revc, >- clear_margins: fbcon_cfb32_clear_margins, >-#else > putc: fbcon_riva32_putc, > putcs: fbcon_riva32_putcs, > revc: fbcon_riva1632_revc, > clear_margins: fbcon_riva32_clear_margins, >-#endif > fontwidthmask: FONTWIDTHRANGE(4, 16) > }; > #endif >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/fbdev.c linux-2.4.22-ppc-dev/drivers/video/riva/fbdev.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/fbdev.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/fbdev.c 2003-08-25 23:38:11.000000000 +0200 >@@ -1,12 +1,9 @@ > /* >- * linux/drivers/video/riva/fbdev.c >+ * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver > * >- * nVidia RIVA 128/TNT/TNT2/GeForce2/3 fb driver >- * >- * Maintained by Ani Joshi <ajoshi@kernel.crashing.org> >+ * Maintained by Ani Joshi <ajoshi@shell.unixbox.com> > * > * Copyright 1999-2000 Jeff Garzik >- * Copyright 2000-2003 Ani Joshi > * > * Contributors: > * >@@ -17,6 +14,10 @@ > * > * Jindrich Makovicka: Accel code help, hw cursor, mtrr > * >+ * Paul Richards: Bug fixes, updates >+ * >+ * Benjamin Herrenschmidt: Fix accel on big endian, PPC fixes >+ * > * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven > * Includes riva_hw.c from nVidia, see copyright below. > * KGI code provided the basis for state storage, init, and mode switching. >@@ -55,10 +56,13 @@ > #error This driver requires PCI support. > #endif > >- >+#include <linux/adb.h> >+#include <linux/pmu.h> >+#include <asm/prom.h> >+#include <asm/pci-bridge.h> > > /* version number of this driver */ >-#define RIVAFB_VERSION "0.9.4" >+#define RIVAFB_VERSION "0.9.4b" > > > >@@ -131,23 +135,43 @@ > CH_RIVA_128 = 0, > CH_RIVA_TNT, > CH_RIVA_TNT2, >- CH_RIVA_UTNT2, /* UTNT2 */ >- CH_RIVA_VTNT2, /* VTNT2 */ >- CH_RIVA_UVTNT2, /* VTNT2 */ >- CH_RIVA_ITNT2, /* ITNT2 */ >+ CH_RIVA_UTNT2, >+ CH_RIVA_VTNT2, >+ CH_RIVA_UVTNT2, >+ CH_RIVA_ITNT2, > CH_GEFORCE_SDR, > CH_GEFORCE_DDR, > CH_QUADRO, > CH_GEFORCE2_MX, >+ CH_GEFORCE2_MX2, >+ CH_GEFORCE2_GO, > CH_QUADRO2_MXR, > CH_GEFORCE2_GTS, >+ CH_GEFORCE2_GTS2, > CH_GEFORCE2_ULTRA, > CH_QUADRO2_PRO, >- CH_GEFORCE2_GO, >- CH_GEFORCE3, >- CH_GEFORCE3_1, >- CH_GEFORCE3_2, >- CH_QUADRO_DDC >+ CH_GEFORCE4_MX_460, >+ CH_GEFORCE4_MX_440, >+ CH_GEFORCE4_MX_420, >+ CH_GEFORCE4_440_GO, >+ CH_GEFORCE4_420_GO, >+ CH_GEFORCE4_420_GO_M32, >+ CH_QUADRO4_500XGL, >+ CH_GEFORCE4_440_GO_M64, >+ CH_QUADRO4_200, >+ CH_QUADRO4_550XGL, >+ CH_QUADRO4_500_GOGL, >+ CH_IGEFORCE2, >+ CH_GEFORCE3, >+ CH_GEFORCE3_1, >+ CH_GEFORCE3_2, >+ CH_QUADRO_DDC, >+ CH_GEFORCE4_TI_4600, >+ CH_GEFORCE4_TI_4400, >+ CH_GEFORCE4_TI_4200, >+ CH_QUADRO4_900XGL, >+ CH_QUADRO4_750XGL, >+ CH_QUADRO4_700XGL > }; > > /* directly indexed by riva_chips enum, above */ >@@ -162,19 +186,39 @@ > { "RIVA-VTNT2", NV_ARCH_04 }, > { "RIVA-UVTNT2", NV_ARCH_04 }, > { "RIVA-ITNT2", NV_ARCH_04 }, >- { "GeForce-SDR", NV_ARCH_10}, >- { "GeForce-DDR", NV_ARCH_10}, >- { "Quadro", NV_ARCH_10}, >- { "GeForce2-MX", NV_ARCH_10}, >- { "Quadro2-MXR", NV_ARCH_10}, >- { "GeForce2-GTS", NV_ARCH_10}, >- { "GeForce2-ULTRA", NV_ARCH_10}, >- { "Quadro2-PRO", NV_ARCH_10}, >- { "GeForce2-Go", NV_ARCH_10}, >- { "GeForce3", NV_ARCH_20}, >- { "GeForce3 Ti 200", NV_ARCH_20}, >- { "GeForce3 Ti 500", NV_ARCH_20}, >- { "Quadro DDC", NV_ARCH_20} >+ { "GeForce-SDR", NV_ARCH_10 }, >+ { "GeForce-DDR", NV_ARCH_10 }, >+ { "Quadro", NV_ARCH_10 }, >+ { "GeForce2-MX", NV_ARCH_10 }, >+ { "GeForce2-MX", NV_ARCH_10 }, >+ { "GeForce2-GO", NV_ARCH_10 }, >+ { "Quadro2-MXR", NV_ARCH_10 }, >+ { "GeForce2-GTS", NV_ARCH_10 }, >+ { "GeForce2-GTS", NV_ARCH_10 }, >+ { "GeForce2-ULTRA", NV_ARCH_10 }, >+ { "Quadro2-PRO", NV_ARCH_10 }, >+ { "GeForce4-MX-460", NV_ARCH_20 }, >+ { "GeForce4-MX-440", NV_ARCH_20 }, >+ { "GeForce4-MX-420", NV_ARCH_20 }, >+ { "GeForce4-440-GO", NV_ARCH_20 }, >+ { "GeForce4-420-GO", NV_ARCH_20 }, >+ { "GeForce4-420-GO-M32", NV_ARCH_20 }, >+ { "Quadro4-500-XGL", NV_ARCH_20 }, >+ { "GeForce4-440-GO-M64", NV_ARCH_20 }, >+ { "Quadro4-200", NV_ARCH_20 }, >+ { "Quadro4-550-XGL", NV_ARCH_20 }, >+ { "Quadro4-500-GOGL", NV_ARCH_20 }, >+ { "GeForce2", NV_ARCH_20 }, >+ { "GeForce3", NV_ARCH_20 }, >+ { "GeForce3 Ti 200", NV_ARCH_20 }, >+ { "GeForce3 Ti 500", NV_ARCH_20 }, >+ { "Quadro DDC", NV_ARCH_20 }, >+ { "GeForce4 Ti 4600", NV_ARCH_20 }, >+ { "GeForce4 Ti 4400", NV_ARCH_20 }, >+ { "GeForce4 Ti 4200", NV_ARCH_20 }, >+ { "Quadro4-900-XGL", NV_ARCH_20 }, >+ { "Quadro4-750-XGL", NV_ARCH_20 }, >+ { "Quadro4-700-XGL", NV_ARCH_20 } > }; > > static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { >@@ -201,27 +245,63 @@ > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX }, > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX }, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX2 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO }, > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_MXR }, > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS2 }, > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA }, > { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, > PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO }, >- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO }, >- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 }, >- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 }, >- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, >- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, >- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_460 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_440 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_420 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO_M32 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500XGL }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO_M64 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_200 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_550XGL }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500_GOGL }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_IGEFORCE2 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4600 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4400 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4200 }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_900XGL }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_750XGL }, >+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, >+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_700XGL }, > { 0, } /* terminate list */ > }; > MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); >@@ -278,12 +358,14 @@ > > /* command line data, set in rivafb_setup() */ > static char fontname[40] __initdata = { 0 }; >-static char noaccel __initdata = 0; >-static char nomove = 0; >-static char nohwcursor __initdata = 0; >-static char noblink = 0; >+static int noaccel __initdata = 0; >+static int nomove = 0; >+static int nohwcursor __initdata = 0; >+static int noblink = 0; >+static int flatpanel __initdata = -1; /* Autodetect later */ >+static int forceCRTC __initdata = -1; > #ifdef CONFIG_MTRR >-static char nomtrr __initdata = 0; >+static int nomtrr __initdata = 0; > #endif > > #ifndef MODULE >@@ -342,7 +424,93 @@ > 0xEB /* MISC */ > }; > >+/* >+ * Here is some specific support for the eMac machine >+ * >+ * This machine is "special" because of it's ivad2 display >+ * controller and fixed horizontal timing requirements. >+ * >+ * Right now, all I do is to set a fixed working 1024x768 >+ * mode at boot (I also have a 1280x960 at hand, if you >+ * prefer...). >+ * >+ * I expect to do things better in a future 2.5 version >+ * though. >+ * >+ * I also turn off the screen during blanking using IVAD >+ * i2c accesses, that's the basis we can use to later >+ * implement full IVAD support (geometry setting, >+ * brightness, ...). >+ */ >+#if defined(CONFIG_ALL_PPC) && defined(CONFIG_ADB_PMU) >+ >+static int ivad_iic_addr = -1; >+ >+/* Default mode for eMac */ >+static struct fb_var_screeninfo emac_default_var = { >+ xres: 1024, >+ yres: 768, >+ xres_virtual: 1024, >+ yres_virtual: 768, >+ xoffset: 0, >+ yoffset: 0, >+ bits_per_pixel: 8, >+ grayscale: 0, >+ red: {0, 6, 0}, >+ green: {0, 6, 0}, >+ blue: {0, 6, 0}, >+ transp: {0, 0, 0}, >+ nonstd: 0, >+ activate: 0, >+ height: -1, >+ width: -1, >+ accel_flags: 0, >+ pixclock: 10081, >+ left_margin: 208, >+ right_margin: 48, >+ upper_margin: 31, >+ lower_margin: 1, >+ hsync_len: 96, >+ vsync_len: 3, >+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, >+ vmode: FB_VMODE_NONINTERLACED >+}; >+ >+static void >+init_ivad(void) >+{ >+ if (machine_is_compatible("PowerMac4,4")) { >+ struct device_node* np = find_devices("ivad2"); >+ unsigned int* prop; >+ >+ if (np == NULL) >+ return; >+ prop = (unsigned int*)get_property(np, "iic-address", NULL); >+ if (np == NULL) { >+ printk(KERN_INFO "IVAD2 found but has no iic-address property !\n"); >+ return; >+ } >+ ivad_iic_addr = *prop; >+ printk(KERN_INFO "Found IVAD2, iic address is: 0x%02x\n", ivad_iic_addr); >+ rivafb_default_var = emac_default_var; >+ } >+} >+ >+#define IVAD_CONTRAST_REG 0x00 >+ >+static void >+set_ivad_contrast(u8 contrast) >+{ >+ int rc; >+ >+ if (ivad_iic_addr < 0) >+ return; >+ rc = pmu_i2c_stdsub_write(PMU_I2C_BUS_POWER, ivad_iic_addr, IVAD_CONTRAST_REG, &contrast, 1); >+ if (rc < 0) >+ printk(KERN_ERR "IVAD2: Can't set contrast !\n"); >+} > >+#endif /* defined(CONFIG_ALL_PPC) && defined(CONFIG_ADB_PMU) */ > > /* ------------------------------------------------------------------------- * > * >@@ -445,7 +613,7 @@ > if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) { > rinfo->cursor->on ^= 1; > if (rinfo->cursor->on) >- *(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF) >+ rinfo->riva.PRAMDAC[0x0000300/4] = (rinfo->cursor->pos.x & 0xFFFF) > | (rinfo->cursor->pos.y << 16); > rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on); > if (!noblink) >@@ -646,7 +814,7 @@ > if (c->last_move_delay <= 1) { /* rapid cursor movement */ > c->vbl_cnt = CURSOR_SHOW_DELAY; > } else { >- *(rinfo->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16); >+ rinfo->riva.PRAMDAC[0x0000300/4] = (x & 0xFFFF) | (y << 16); > rinfo->riva.ShowHideCursor(&rinfo->riva, 1); > if (!noblink) c->vbl_cnt = CURSOR_HIDE_DELAY; > c->on = 1; >@@ -886,9 +1054,10 @@ > hEnd = (hDisplaySize + video_mode->right_margin + > video_mode->hsync_len) / 8 - 1; > hTotal = (hDisplaySize + video_mode->right_margin + >- video_mode->hsync_len + video_mode->left_margin) / 8 - 1; >+ video_mode->hsync_len + video_mode->left_margin) / 8 - 5; > hBlankStart = hDisplay; >- hBlankEnd = hTotal; >+ hBlankEnd = hTotal + 4; >+ > height = video_mode->yres_virtual; > vDisplay = video_mode->yres - 1; > vStart = video_mode->yres + video_mode->lower_margin - 1; >@@ -897,28 +1066,12 @@ > vTotal = video_mode->yres + video_mode->lower_margin + > video_mode->vsync_len + video_mode->upper_margin + 2; > vBlankStart = vDisplay; >- vBlankEnd = vTotal; >+ vBlankEnd = vTotal + 1; > dotClock = 1000000000 / video_mode->pixclock; > > memcpy(&newmode, ®_template, sizeof(struct riva_regs)); > >- newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4) >- | SetBitField(vBlankStart,10:10,3:3) >- | SetBitField(vStart,10:10,2:2) >- | SetBitField(vDisplay,10:10,1:1) >- | SetBitField(vTotal,10:10,0:0); >- >- newmode.ext.horiz = SetBitField(hTotal,8:8,0:0) >- | SetBitField(hDisplay,8:8,1:1) >- | SetBitField(hBlankStart,8:8,2:2) >- | SetBitField(hStart,8:8,3:3); >- >- newmode.ext.extra = SetBitField(vTotal,11:11,0:0) >- | SetBitField(vDisplay,11:11,2:2) >- | SetBitField(vStart,11:11,4:4) >- | SetBitField(vBlankStart,11:11,6:6); >- >- if (rinfo->riva.flatPanel) { >+ if (rinfo->FlatPanel) { > vStart = vTotal - 3; > vEnd = vTotal - 2; > vBlankStart = vStart; >@@ -927,14 +1080,13 @@ > hBlankEnd = hTotal + 4; > } > >- newmode.crtc[0x0] = Set8Bits (hTotal - 4); >+ newmode.crtc[0x0] = Set8Bits (hTotal); > newmode.crtc[0x1] = Set8Bits (hDisplay); > newmode.crtc[0x2] = Set8Bits (hBlankStart); >- newmode.crtc[0x3] = SetBitField(hBlankEnd,4:0,4:0) >- | SetBit(7); >+ newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7); > newmode.crtc[0x4] = Set8Bits (hStart); > newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7) >- | SetBitField (hEnd, 4: 0, 4:0); >+ | SetBitField (hEnd, 4: 0, 4:0); > newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0); > newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0) > | SetBitField (vDisplay, 8: 8, 1:1) >@@ -950,37 +1102,64 @@ > newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0) > | SetBit (5); > newmode.crtc[0x12] = Set8Bits (vDisplay); >- newmode.crtc[0x13] = ((width / 8) * ((bpp + 1) / 8)) & 0xFF; >+ newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8); > newmode.crtc[0x15] = Set8Bits (vBlankStart); > newmode.crtc[0x16] = Set8Bits (vBlankEnd); > >+ newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4) >+ | SetBitField(vBlankStart,10:10,3:3) >+ | SetBitField(vStart,10:10,2:2) >+ | SetBitField(vDisplay,10:10,1:1) >+ | SetBitField(vTotal,10:10,0:0); >+ newmode.ext.horiz = SetBitField(hTotal,8:8,0:0) >+ | SetBitField(hDisplay,8:8,1:1) >+ | SetBitField(hBlankStart,8:8,2:2) >+ | SetBitField(hStart,8:8,3:3); >+ newmode.ext.extra = SetBitField(vTotal,11:11,0:0) >+ | SetBitField(vDisplay,11:11,2:2) >+ | SetBitField(vStart,11:11,4:4) >+ | SetBitField(vBlankStart,11:11,6:6); >+ >+ /* CalcStateExt does this already */ >+ /* > newmode.ext.bpp = bpp; > newmode.ext.width = width; > newmode.ext.height = height; >+ */ >+ newmode.ext.interlace = 0xff; /* interlace off */ >+ >+ if(rinfo->riva.Architecture >= NV_ARCH_10) >+ rinfo->riva.CURSOR = (U032 *)(rinfo->fb_base + rinfo->riva.CursorStart); > > rinfo->riva.CalcStateExt(&rinfo->riva, &newmode.ext, bpp, width, >- hDisplaySize, hDisplay, hStart, hEnd, >- hTotal, height, vDisplay, vStart, vEnd, >- vTotal, dotClock); >+ hDisplaySize, height, dotClock); > > newmode.ext.scale = rinfo->riva.PRAMDAC[0x00000848/4] & 0xfff000ff; >- >- if (rinfo->riva.flatPanel) { >+ if(rinfo->FlatPanel == 1) { > newmode.ext.pixel |= (1 << 7); >- newmode.ext.scale |= (1 << 8); >+ newmode.ext.scale |= (1 << 8) ; > } >- >- newmode.ext.vpll2 = rinfo->riva.PRAMDAC[0x00000520/4]; >- >-#if defined(__powerpc__) >- /* >- * XXX only Mac cards use second DAC for flat panel >- */ >- if (rinfo->riva.flatPanel) { >+ if(rinfo->SecondCRTC) { >+ newmode.ext.head = rinfo->riva.PCRTC0[0x00000860/4] & ~0x00001000; >+ newmode.ext.head2 = rinfo->riva.PCRTC0[0x00002860/4] | 0x00001000; >+ newmode.ext.crtcOwner = 3; > newmode.ext.pllsel |= 0x20000800; > newmode.ext.vpll2 = newmode.ext.vpll; >+ } else if(rinfo->riva.twoHeads) { >+ newmode.ext.head = rinfo->riva.PCRTC0[0x00000860/4] | 0x00001000; >+ newmode.ext.head2 = rinfo->riva.PCRTC0[0x00002860/4] & ~0x00001000; >+ newmode.ext.crtcOwner = 0; >+ newmode.ext.vpll2 = rinfo->riva.PRAMDAC0[0x00000520/4]; > } >-#endif >+ >+ newmode.ext.cursorConfig = 0x02000100; >+ >+ newmode.misc_output &= 0x3f; >+ if ((video_mode->sync & FB_SYNC_HOR_HIGH_ACT) == 0) >+ newmode.misc_output |= 0x40; >+ if ((video_mode->sync & FB_SYNC_VERT_HIGH_ACT) == 0) >+ newmode.misc_output |= 0x80; >+ > rinfo->current_state = newmode; > riva_load_state(rinfo, &rinfo->current_state); > >@@ -1463,6 +1642,12 @@ > > accel = v.accel_flags & FB_ACCELF_TEXT; > >+ /* Accel seem to not work properly on GeForce4's yet...*/ >+ if (rivainfo->riva.Architecture == NV_ARCH_20) { >+ v.accel_flags &= ~FB_ACCELF_TEXT; >+ accel = 0; >+ } >+ > switch (v.bits_per_pixel) { > #ifdef FBCON_HAS_CFB8 > case 1 ... 8: >@@ -1802,6 +1987,13 @@ > vesa |= 0xc0; > break; > } >+#if defined(CONFIG_ALL_PPC) && defined(CONFIG_ADB_PMU) >+ set_ivad_contrast(0); >+#endif >+ } else { >+#if defined(CONFIG_ALL_PPC) && defined(CONFIG_ADB_PMU) >+ set_ivad_contrast(0xff); >+#endif > } > > SEQout(rinfo, 0x01, tmp); >@@ -1841,7 +2033,7 @@ > if (rinfo->use_default_var) > /* We will use the modified default var */ > rinfo->disp.var = rivafb_default_var; >- >+ > return 0; > } > >@@ -1877,6 +2069,14 @@ > > riva_set_dispsw(rinfo, disp); > >+ if (disp->var.accel_flags & FB_ACCELF_TEXT) { >+ if (nomove) >+ disp->scrollmode = SCROLL_YNOMOVE; >+ else >+ disp->scrollmode = 0; >+ } else >+ disp->scrollmode = SCROLL_YREDRAW; >+ > DPRINTK("EXIT, returning 0\n"); > return 0; > >@@ -1913,19 +2113,37 @@ > } > > #ifdef CONFIG_ALL_PPC >+/* >+ * For now we only retreive EDID for flat panels, we'll fix that >+ * once we know what to do of non-flat panel EDIDs, that is typically >+ * in 2.5 --BenH. >+ */ > static int riva_get_EDID_OF(struct rivafb_info *rinfo) > { >- struct device_node *dp; >- unsigned char *pedid = NULL; >- >- dp = pci_device_to_OF_node(rinfo->pd); >- pedid = (unsigned char *)get_property(dp, "EDID,B", 0); >- >- if (pedid) { >- rinfo->EDID = pedid; >- return 1; >- } else >- return 0; >+ struct device_node *dp; >+ unsigned char *pedid = NULL; >+ unsigned char *disptype = NULL; >+ static char *propnames[] = { >+ "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; >+ int i; >+ >+ dp = pci_device_to_OF_node(rinfo->pd); >+ for (; dp != NULL; dp = dp->child) { >+ disptype = (unsigned char *)get_property(dp, "display-type", NULL); >+ if (disptype == NULL) >+ continue; >+ if (strncmp(disptype, "LCD", 3) != 0) >+ continue; >+ for (i = 0; propnames[i] != NULL; ++i) { >+ pedid = (unsigned char *) >+ get_property(dp, propnames[i], NULL); >+ if (pedid != NULL) { >+ rinfo->EDID = pedid; >+ return 1; >+ } >+ } >+ } >+ return 0; > } > #endif /* CONFIG_ALL_PPC */ > >@@ -1939,28 +2157,29 @@ > /* jump to detailed timing block section */ > block += 54; > >- rinfo->clock = (block[0] + (block[1] << 8)); >- rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4)); >- rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8)); >- rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4)); >- rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8)); >- rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2)); >- rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4)); >- rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2)); >- rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4)); >- rinfo->interlaced = ((block[17] & 0x80) >> 7); >- rinfo->synct = ((block[17] & 0x18) >> 3); >- rinfo->misc = ((block[17] & 0x06) >> 1); >- rinfo->hAct_high = rinfo->vAct_high = 0; >- if (rinfo->synct == 3) { >- if (rinfo->misc & 2) >- rinfo->hAct_high = 1; >- if (rinfo->misc & 1) >- rinfo->vAct_high = 1; >+ rinfo->clock = (block[0] + (block[1] << 8)); >+ rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4)); >+ rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8)); >+ rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4)); >+ rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8)); >+ rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2)); >+ rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4)); >+ rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2)); >+ rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4)); >+ rinfo->interlaced = ((block[17] & 0x80) >> 7); >+ rinfo->synct = ((block[17] & 0x18) >> 3); >+ rinfo->misc = ((block[17] & 0x06) >> 1); >+ rinfo->hAct_high = rinfo->vAct_high = 0; >+ if (rinfo->synct == 3) { >+ if (rinfo->misc & 2) >+ rinfo->hAct_high = 1; >+ if (rinfo->misc & 1) >+ rinfo->vAct_high = 1; > } > >- printk("rivafb: detected DFP panel size from EDID: %dx%d\n", >- rinfo->panel_xres, rinfo->panel_yres); >+ printk(KERN_INFO PFX >+ "detected DFP panel size from EDID: %dx%d\n", >+ rinfo->panel_xres, rinfo->panel_yres); > > rinfo->got_dfpinfo = 1; > >@@ -2020,7 +2239,8 @@ > if (riva_dfp_parse_EDID(rinfo)) > riva_update_default_var(rinfo); > >- rinfo->riva.flatPanel = rinfo->got_dfpinfo; >+ if (rinfo->FlatPanel == -1 && rinfo->got_dfpinfo == 1) /* if user specified flatpanel, we respect that */ >+ rinfo->FlatPanel = 1; > } > > >@@ -2049,6 +2269,14 @@ > rinfo->drvr_name = rci->name; > rinfo->riva.Architecture = rci->arch_rev; > >+ rinfo->Chipset = (pd->vendor << 16) | pd->device; >+ printk(KERN_INFO PFX "nVidia device/chipset %X\n", rinfo->Chipset); >+ >+ rinfo->FlatPanel = flatpanel; >+ if (flatpanel == 1) >+ printk(KERN_INFO PFX "flatpanel support enabled\n"); >+ rinfo->forceCRTC = forceCRTC; >+ > rinfo->pd = pd; > rinfo->base0_region_size = pci_resource_len(pd, 0); > rinfo->base1_region_size = pci_resource_len(pd, 1); >@@ -2061,104 +2289,69 @@ > cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); > pci_write_config_word(pd, PCI_COMMAND, cmd); > } >- >+ > rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0); > rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1); > >+ if (!request_mem_region(rinfo->ctrl_base_phys, >+ rinfo->base0_region_size, "rivafb")) { >+ printk(KERN_ERR PFX "cannot reserve MMIO region\n"); >+ goto err_out_kfree; >+ } >+ > rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys, > rinfo->base0_region_size); > if (!rinfo->ctrl_base) { > printk(KERN_ERR PFX "cannot ioremap MMIO base\n"); >- goto err_out_free_base1; >+ goto err_out_free_base0; > } > > riva_get_EDID(rinfo); > > riva_get_dfpinfo(rinfo); > >- rinfo->riva.EnableIRQ = 0; >- rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000); >- rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000); >- rinfo->riva.PFIFO = (unsigned *)(rinfo->ctrl_base + 0x00002000); >- rinfo->riva.PGRAPH = (unsigned *)(rinfo->ctrl_base + 0x00400000); >- rinfo->riva.PEXTDEV = (unsigned *)(rinfo->ctrl_base + 0x00101000); >- rinfo->riva.PTIMER = (unsigned *)(rinfo->ctrl_base + 0x00009000); >- rinfo->riva.PMC = (unsigned *)(rinfo->ctrl_base + 0x00000000); >- rinfo->riva.FIFO = (unsigned *)(rinfo->ctrl_base + 0x00800000); >- >- rinfo->riva.PCIO = (U008 *)(rinfo->ctrl_base + 0x00601000); >- rinfo->riva.PDIO = (U008 *)(rinfo->ctrl_base + 0x00681000); >- rinfo->riva.PVIO = (U008 *)(rinfo->ctrl_base + 0x000C0000); >- >- rinfo->riva.IO = (MISCin(rinfo) & 0x01) ? 0x3D0 : 0x3B0; >- >- if (rinfo->riva.Architecture == NV_ARCH_03) { >- /* >- * We have to map the full BASE_1 aperture for Riva128's >- * because they use the PRAMIN set in "framebuffer" space >+ switch (rinfo->riva.Architecture) { >+ case NV_ARCH_03: >+ /* Riva128's PRAMIN is in the "framebuffer" space >+ * Since these cards were never made with more than 8 megabytes >+ * we can safely allocate this seperately. > */ >- if (!request_mem_region(rinfo->fb_base_phys, >- rinfo->base1_region_size, "rivafb")) { >- printk(KERN_ERR PFX "cannot reserve FB region\n"); >- goto err_out_free_base0; >- } >- >- rinfo->fb_base = ioremap(rinfo->fb_base_phys, >- rinfo->base1_region_size); >- if (!rinfo->fb_base) { >- printk(KERN_ERR PFX "cannot ioremap FB base\n"); >+ if (!request_mem_region(rinfo->fb_base_phys + 0x00C00000, >+ 0x00008000, "rivafb")) { >+ printk(KERN_ERR PFX "cannot reserve PRAMIN region\n"); > goto err_out_iounmap_ctrl; > } >- } >- >- >- switch (rinfo->riva.Architecture) { >- case NV_ARCH_03: >- rinfo->riva.PRAMIN = (unsigned *)(rinfo->fb_base + 0x00C00000); >+ rinfo->riva.PRAMIN = ioremap(rinfo->fb_base_phys + 0x00C00000, >+ 0x00008000); >+ if (!rinfo->riva.PRAMIN) { >+ printk(KERN_ERR PFX "cannot ioremap PRAMIN region\n"); >+ goto err_out_free_nv3_pramin; >+ } > break; > case NV_ARCH_04: > case NV_ARCH_10: > case NV_ARCH_20: >- rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000); >+ rinfo->riva.PCRTC0 = (unsigned *)(rinfo->ctrl_base + 0x00600000); > rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000); > break; > } > >-#if defined(__powerpc__) >- /* >- * XXX Mac cards use the second DAC for the panel >- */ >- if (rinfo->riva.flatPanel) { >- printk("rivafb: using second CRTC\n"); >- rinfo->riva.PCIO = rinfo->riva.PCIO + 0x2000; >- rinfo->riva.PCRTC = rinfo->riva.PCRTC + 0x800; >- rinfo->riva.PRAMDAC = rinfo->riva.PRAMDAC + 0x800; >- rinfo->riva.PDIO = rinfo->riva.PDIO + 0x2000; >- } >-#endif >- >- RivaGetConfig(&rinfo->riva); >+ riva_common_setup(rinfo); > > rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024; > rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000; > >- if (rinfo->riva.Architecture != NV_ARCH_03) { >- /* >- * Now the _normal_ chipsets can just map the amount of >- * real physical ram instead of the whole aperture >- */ >- if (!request_mem_region(rinfo->fb_base_phys, >- rinfo->ram_amount, "rivafb")) { >- printk(KERN_ERR PFX "cannot reserve FB region\n"); >- goto err_out_free_base0; >- } >+ if (!request_mem_region(rinfo->fb_base_phys, >+ rinfo->ram_amount, "rivafb")) { >+ printk(KERN_ERR PFX "cannot reserve FB region\n"); >+ goto err_out_iounmap_nv3_pramin; >+ } > >- rinfo->fb_base = ioremap(rinfo->fb_base_phys, >- rinfo->ram_amount); >- if (!rinfo->fb_base) { >- printk(KERN_ERR PFX "cannot ioremap FB base\n"); >- goto err_out_iounmap_ctrl; >- } >+ rinfo->fb_base = ioremap(rinfo->fb_base_phys, >+ rinfo->ram_amount); >+ if (!rinfo->fb_base) { >+ printk(KERN_ERR PFX "cannot ioremap FB base\n"); >+ goto err_out_free_base1; > } > > #ifdef CONFIG_MTRR >@@ -2215,10 +2408,16 @@ > rivafb_exit_cursor(rinfo); > /* err_out_iounmap_fb: */ > iounmap(rinfo->fb_base); >+err_out_free_base1: >+ release_mem_region(rinfo->fb_base_phys, rinfo->ram_amount); >+err_out_iounmap_nv3_pramin: >+ if (rinfo->riva.Architecture == NV_ARCH_03) >+ iounmap((caddr_t)rinfo->riva.PRAMIN); >+err_out_free_nv3_pramin: >+ if (rinfo->riva.Architecture == NV_ARCH_03) >+ release_mem_region(rinfo->fb_base_phys + 0x00C00000, 0x00008000); > err_out_iounmap_ctrl: > iounmap(rinfo->ctrl_base); >-err_out_free_base1: >- release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size); > err_out_free_base0: > release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size); > err_out_kfree: >@@ -2256,6 +2455,11 @@ > release_mem_region(board->fb_base_phys, > board->ram_amount); > >+ if (board->riva.Architecture == NV_ARCH_03) { >+ iounmap((caddr_t)board->riva.PRAMIN); >+ release_mem_region(board->fb_base_phys + 0x00C00000, 0x00008000); >+ } >+ > kfree(board); > > pci_set_drvdata(pd, NULL); >@@ -2301,6 +2505,16 @@ > } else if (!strncmp(this_opt, "nomtrr", 6)) { > nomtrr = 1; > #endif >+ } else if (!strncmp(this_opt, "forceCRTC", 9)) { >+ char *p; >+ >+ p = this_opt + 9; >+ if (!*p || !*(++p)) continue; >+ forceCRTC = *p - '0'; >+ if (forceCRTC < 0 || forceCRTC > 1) >+ forceCRTC = -1; >+ } else if (!strncmp(this_opt, "flatpanel", 9)) { >+ flatpanel = 1; > } else if (!strncmp(this_opt, "nohwcursor", 10)) { > nohwcursor = 1; > } else >@@ -2331,9 +2545,13 @@ > #ifdef MODULE > if (font) strncpy(fontname, font, sizeof(fontname)-1); > #endif >+#if defined(CONFIG_ALL_PPC) && defined(CONFIG_ADB_PMU) >+ init_ivad(); >+#endif > err = pci_module_init(&rivafb_driver); > if (err) > return err; >+ pci_register_driver(&rivafb_driver); > return 0; > } > >@@ -2357,6 +2575,11 @@ > MODULE_PARM_DESC(nohwcursor, "Disables hardware cursor (0 or 1=disabled) (default=0)"); > MODULE_PARM(noblink, "i"); > MODULE_PARM_DESC(noblink, "Disables hardware cursor blinking (0 or 1=disabled) (default=0)"); >+MODULE_PARM(flatpanel, "i"); >+MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)"); >+MODULE_PARM(forceCRTC, "i"); >+MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)"); >+ > #ifdef CONFIG_MTRR > MODULE_PARM(nomtrr, "i"); > MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)"); >@@ -2364,5 +2587,5 @@ > #endif /* MODULE */ > > MODULE_AUTHOR("Ani Joshi, maintainer"); >-MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2"); >+MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2, and the GeForce series"); > MODULE_LICENSE("GPL"); >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/nv4ref.h linux-2.4.22-ppc-dev/drivers/video/riva/nv4ref.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/nv4ref.h 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/nv4ref.h 2003-08-25 23:38:11.000000000 +0200 >@@ -41,7 +41,7 @@ > * GPL licensing note -- nVidia is allowing a liberal interpretation of > * the documentation restriction above, to merely say that this nVidia's > * copyright and disclaimer should be included with all code derived >- * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 >+ * from this source. -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 > */ > > /***************************************************************************\ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/nv_setup.c linux-2.4.22-ppc-dev/drivers/video/riva/nv_setup.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/nv_setup.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/nv_setup.c 2003-08-25 23:37:41.000000000 +0200 >@@ -0,0 +1,262 @@ >+/* $XConsortium: nv_driver.c /main/3 1996/10/28 05:13:37 kaleb $ */ >+/* >+ * Copyright 1996-1997 David J. McKay >+ * >+ * Permission is hereby granted, free of charge, to any person obtaining a >+ * copy of this software and associated documentation files (the "Software"), >+ * to deal in the Software without restriction, including without limitation >+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, >+ * and/or sell copies of the Software, and to permit persons to whom the >+ * Software is furnished to do so, subject to the following conditions: >+ * >+ * The above copyright notice and this permission notice shall be included in >+ * all copies or substantial portions of the Software. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL >+ * DAVID J. MCKAY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, >+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF >+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE >+ * SOFTWARE. >+ */ >+ >+/* >+ * GPL licensing note -- nVidia is allowing a liberal interpretation of >+ * the documentation restriction above, to merely say that this nVidia's >+ * copyright and disclaimer should be included with all code derived >+ * from this source. -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 >+ */ >+ >+/* Hacked together from mga driver and 3.3.4 NVIDIA driver by Jarno Paananen >+ <jpaana@s2.org> */ >+ >+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_setup.c,v 1.18 2002/08/0 >+5 20:47:06 mvojkovi Exp $ */ >+ >+#include <linux/delay.h> >+#include <linux/pci_ids.h> >+#include "nv_type.h" >+#include "rivafb.h" >+#include "nvreg.h" >+ >+ >+#ifndef CONFIG_PCI /* sanity check */ >+#error This driver requires PCI support. >+#endif >+ >+#define PFX "rivafb: " >+ >+static inline unsigned char MISCin(struct rivafb_info *rinfo) >+{ >+ return (VGA_RD08(rinfo->riva.PVIO, 0x3cc)); >+} >+ >+static Bool >+riva_is_connected(struct rivafb_info *rinfo, Bool second) >+{ >+ volatile U032 *PRAMDAC = rinfo->riva.PRAMDAC0; >+ U032 reg52C, reg608; >+ Bool present; >+ >+ if(second) PRAMDAC += 0x800; >+ >+ reg52C = PRAMDAC[0x052C/4]; >+ reg608 = PRAMDAC[0x0608/4]; >+ >+ PRAMDAC[0x0608/4] = reg608 & ~0x00010000; >+ >+ PRAMDAC[0x052C/4] = reg52C & 0x0000FEEE; >+ mdelay(1); >+ PRAMDAC[0x052C/4] |= 1; >+ >+ rinfo->riva.PRAMDAC0[0x0610/4] = 0x94050140; >+ rinfo->riva.PRAMDAC0[0x0608/4] |= 0x00001000; >+ >+ mdelay(1); >+ >+ present = (PRAMDAC[0x0608/4] & (1 << 28)) ? TRUE : FALSE; >+ >+ rinfo->riva.PRAMDAC0[0x0608/4] &= 0x0000EFFF; >+ >+ PRAMDAC[0x052C/4] = reg52C; >+ PRAMDAC[0x0608/4] = reg608; >+ >+ return present; >+} >+ >+static void >+riva_override_CRTC(struct rivafb_info *rinfo) >+{ >+ printk(KERN_INFO PFX >+ "Detected CRTC controller %i being used\n", >+ rinfo->SecondCRTC ? 1 : 0); >+ >+ if(rinfo->forceCRTC != -1) { >+ printk(KERN_INFO PFX >+ "Forcing usage of CRTC %i\n", rinfo->forceCRTC); >+ rinfo->SecondCRTC = rinfo->forceCRTC; >+ } >+} >+ >+static void >+riva_is_second(struct rivafb_info *rinfo) >+{ >+ if(rinfo->FlatPanel == 1) { >+ switch(rinfo->Chipset & 0xffff) { >+ case 0x0174: >+ case 0x0175: >+ case 0x0176: >+ case 0x0177: >+ case 0x0179: >+ case 0x017C: >+ case 0x017D: >+ case 0x0186: >+ case 0x0187: >+ /* this might not be a good default for the chips below */ >+ case 0x0286: >+ case 0x028C: >+ case 0x0316: >+ case 0x0317: >+ case 0x031A: >+ case 0x031B: >+ case 0x031C: >+ case 0x031D: >+ case 0x031E: >+ case 0x031F: >+ case 0x0324: >+ case 0x0325: >+ case 0x0328: >+ case 0x0329: >+ case 0x032C: >+ case 0x032D: >+ rinfo->SecondCRTC = TRUE; >+ break; >+ default: >+ rinfo->SecondCRTC = FALSE; >+ break; >+ } >+ } else { >+ if(riva_is_connected(rinfo, 0)) { >+ if(rinfo->riva.PRAMDAC0[0x0000052C/4] & 0x100) >+ rinfo->SecondCRTC = TRUE; >+ else >+ rinfo->SecondCRTC = FALSE; >+ } else >+ if (riva_is_connected(rinfo, 1)) { >+ if(rinfo->riva.PRAMDAC0[0x0000252C/4] & 0x100) >+ rinfo->SecondCRTC = TRUE; >+ else >+ rinfo->SecondCRTC = FALSE; >+ } else /* default */ >+ rinfo->SecondCRTC = FALSE; >+ } >+ >+ riva_override_CRTC(rinfo); >+} >+ >+void >+riva_common_setup(struct rivafb_info *rinfo) >+{ >+ rinfo->riva.EnableIRQ = 0; >+ rinfo->riva.PRAMDAC0 = (unsigned *)(rinfo->ctrl_base + 0x00680000); >+ rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000); >+ rinfo->riva.PFIFO = (unsigned *)(rinfo->ctrl_base + 0x00002000); >+ rinfo->riva.PGRAPH = (unsigned *)(rinfo->ctrl_base + 0x00400000); >+ rinfo->riva.PEXTDEV = (unsigned *)(rinfo->ctrl_base + 0x00101000); >+ rinfo->riva.PTIMER = (unsigned *)(rinfo->ctrl_base + 0x00009000); >+ rinfo->riva.PMC = (unsigned *)(rinfo->ctrl_base + 0x00000000); >+ rinfo->riva.FIFO = (unsigned *)(rinfo->ctrl_base + 0x00800000); >+ rinfo->riva.PCIO0 = (U008 *)(rinfo->ctrl_base + 0x00601000); >+ rinfo->riva.PDIO0 = (U008 *)(rinfo->ctrl_base + 0x00681000); >+ rinfo->riva.PVIO = (U008 *)(rinfo->ctrl_base + 0x000C0000); >+ >+ rinfo->riva.IO = (MISCin(rinfo) & 0x01) ? 0x3D0 : 0x3B0; >+ >+ if(rinfo->FlatPanel == -1) { >+ switch(rinfo->Chipset) { >+ case 0x0112: /* known laptop chips */ >+ case 0x0174: >+ case 0x0175: >+ case 0x0176: >+ case 0x0177: >+ case 0x0179: >+ case 0x017C: >+ case 0x017D: >+ case 0x0186: >+ case 0x0187: >+ case 0x0286: >+ case 0x028C: >+ case 0x0316: >+ case 0x0317: >+ case 0x031A: >+ case 0x031B: >+ case 0x031C: >+ case 0x031D: >+ case 0x031E: >+ case 0x031F: >+ case 0x0324: >+ case 0x0325: >+ case 0x0328: >+ case 0x0329: >+ case 0x032C: >+ case 0x032D: >+ printk(KERN_INFO PFX >+ "On a laptop. Assuming Digital Flat Panel\n"); >+ rinfo->FlatPanel = 1; >+ break; >+ default: >+ break; >+ } >+ } >+ >+ switch (rinfo->Chipset & 0x0ff0) { >+ case 0x0110: >+ if (rinfo->Chipset == NV_CHIP_GEFORCE2_GO) >+ rinfo->SecondCRTC = TRUE; >+#if defined(__powerpc__) >+ if (rinfo->FlatPanel == 1) >+ rinfo->SecondCRTC = TRUE; >+#endif >+ riva_override_CRTC(rinfo); >+ break; >+ case 0x0170: >+ case 0x0180: >+ case 0x01F0: >+ case 0x0250: >+ case 0x0280: >+ case 0x0300: >+ case 0x0310: >+ case 0x0320: >+ case 0x0330: >+ case 0x0340: >+ riva_is_second(rinfo); >+ break; >+ default: >+ break; >+ } >+ >+ if (rinfo->riva.Architecture == NV_ARCH_03) >+ rinfo->riva.PCRTC = rinfo->riva.PCRTC0 = rinfo->riva.PGRAPH; >+ >+ if (rinfo->SecondCRTC) { >+ rinfo->riva.PCIO = rinfo->riva.PCIO0 + 0x2000; >+ rinfo->riva.PCRTC = rinfo->riva.PCRTC0 + 0x800; >+ rinfo->riva.PRAMDAC = rinfo->riva.PRAMDAC0 + 0x800; >+ rinfo->riva.PDIO = rinfo->riva.PDIO0 + 0x2000; >+ } else { >+ rinfo->riva.PCIO = rinfo->riva.PCIO0; >+ rinfo->riva.PCRTC = rinfo->riva.PCRTC0; >+ rinfo->riva.PRAMDAC = rinfo->riva.PRAMDAC0; >+ rinfo->riva.PDIO = rinfo->riva.PDIO0; >+ } >+ >+ RivaGetConfig(&rinfo->riva, rinfo->Chipset); >+ >+ if (rinfo->FlatPanel == -1) { >+ /* Fix me, need x86 DDC code */ >+ rinfo->FlatPanel = 0; >+ } >+ rinfo->riva.flatPanel = (rinfo->FlatPanel > 0) ? TRUE : FALSE; >+} >+ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/nv_type.h linux-2.4.22-ppc-dev/drivers/video/riva/nv_type.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/nv_type.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/nv_type.h 2003-08-25 23:37:35.000000000 +0200 >@@ -0,0 +1,58 @@ >+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_type.h,v 1.35 2002/08/05 20:47:06 mvojkovi Exp $ */ >+ >+#ifndef __NV_STRUCT_H__ >+#define __NV_STRUCT_H__ >+ >+#define NV_CHIP_RIVA_128 ((PCI_VENDOR_ID_NVIDIA_SGS << 16)| PCI_DEVICE_ID_NVIDIA_RIVA128) >+#define NV_CHIP_TNT ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT) >+#define NV_CHIP_TNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_TNT2) >+#define NV_CHIP_UTNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UTNT2) >+#define NV_CHIP_VTNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_VTNT2) >+#define NV_CHIP_UVTNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_UVTNT2) >+#define NV_CHIP_ITNT2 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_ITNT2) >+#define NV_CHIP_GEFORCE_256 ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_256) >+#define NV_CHIP_GEFORCE_DDR ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR) >+#define NV_CHIP_QUADRO ((PCI_VENDOR_ID_NVIDIA << 16)| PCI_DEVICE_ID_NVIDIA_QUADRO) >+#define NV_CHIP_GEFORCE2_MX ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX) >+#define NV_CHIP_GEFORCE2_MX_100 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX_100) >+#define NV_CHIP_QUADRO2_MXR ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR) >+#define NV_CHIP_GEFORCE2_GO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO) >+#define NV_CHIP_GEFORCE2_GTS ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS) >+#define NV_CHIP_GEFORCE2_TI ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_TI) >+#define NV_CHIP_GEFORCE2_ULTRA ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA) >+#define NV_CHIP_QUADRO2_PRO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO) >+#define NV_CHIP_GEFORCE4_MX_460 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460) >+#define NV_CHIP_GEFORCE4_MX_440 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440) >+#define NV_CHIP_GEFORCE4_MX_420 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420) >+#define NV_CHIP_GEFORCE4_440_GO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO) >+#define NV_CHIP_GEFORCE4_420_GO ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO) >+#define NV_CHIP_GEFORCE4_420_GO_M32 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32) >+#define NV_CHIP_QUADRO4_500XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL) >+#define NV_CHIP_GEFORCE4_440_GO_M64 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64) >+#define NV_CHIP_QUADRO4_200 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_200) >+#define NV_CHIP_QUADRO4_550XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL) >+#define NV_CHIP_QUADRO4_500_GOGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL) >+#define NV_CHIP_0x0180 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0180) >+#define NV_CHIP_0x0181 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0181) >+#define NV_CHIP_0x0182 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0182) >+#define NV_CHIP_0x0188 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0188) >+#define NV_CHIP_0x018A ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018A) >+#define NV_CHIP_0x018B ((PCI_VENDOR_ID_NVIDIA << 16) | 0x018B) >+#define NV_CHIP_IGEFORCE2 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_IGEFORCE2) >+#define NV_CHIP_0x01F0 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x01F0) >+#define NV_CHIP_GEFORCE3 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3) >+#define NV_CHIP_GEFORCE3_TI_200 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_200) >+#define NV_CHIP_GEFORCE3_TI_500 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE3_TI_500) >+#define NV_CHIP_QUADRO_DCC ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO_DCC) >+#define NV_CHIP_GEFORCE4_TI_4600 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600) >+#define NV_CHIP_GEFORCE4_TI_4400 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400) >+#define NV_CHIP_GEFORCE4_TI_4200 ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200) >+#define NV_CHIP_QUADRO4_900XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL) >+#define NV_CHIP_QUADRO4_750XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL) >+#define NV_CHIP_QUADRO4_700XGL ((PCI_VENDOR_ID_NVIDIA << 16) | PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL) >+#define NV_CHIP_0x0280 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0280) >+#define NV_CHIP_0x0281 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0281) >+#define NV_CHIP_0x0288 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0288) >+#define NV_CHIP_0x0289 ((PCI_VENDOR_ID_NVIDIA << 16) | 0x0289) >+ >+#endif /* __NV_STRUCT_H__ */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/riva_hw.c linux-2.4.22-ppc-dev/drivers/video/riva/riva_hw.c >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/riva_hw.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/riva_hw.c 2003-08-25 23:38:04.000000000 +0200 >@@ -41,13 +41,17 @@ > * GPL licensing note -- nVidia is allowing a liberal interpretation of > * the documentation restriction above, to merely say that this nVidia's > * copyright and disclaimer should be included with all code derived >- * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 >+ * from this source. -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 > */ > >-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.8 2000/02/08 17:19:11 dawes Exp $ */ >+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.33 2002/08/05 20:47:06 mvojkovi Exp $ */ > >+#include <linux/pci_ids.h> >+#include <linux/pci.h> > #include "riva_hw.h" > #include "riva_tbl.h" >+#include "nv_type.h" >+ > /* > * This file is an OS-agnostic file used to make RIVA 128 and RIVA TNT > * operate identically (except TNT has more memory and better 3D quality. >@@ -73,32 +77,39 @@ > { > return ((chip->Rop->FifoFree < chip->FifoEmptyCount) || (chip->PGRAPH[0x00000700/4] & 0x01)); > } >-static void nv3LockUnlock >+ >+static void vgaLockUnlock > ( > RIVA_HW_INST *chip, >- int LockUnlock >+ int Lock > ) > { >- VGA_WR08(chip->PVIO, 0x3C4, 0x06); >- VGA_WR08(chip->PVIO, 0x3C5, LockUnlock ? 0x99 : 0x57); >+ U008 cr11; >+ VGA_WR08(chip->PCIO, 0x3D4, 0x11); >+ cr11 = VGA_RD08(chip->PCIO, 0x3D5); >+ if(Lock) cr11 |= 0x80; >+ else cr11 &= ~0x80; >+ VGA_WR08(chip->PCIO, 0x3D5, cr11); > } >-static void nv4LockUnlock >+static void nv3LockUnlock > ( > RIVA_HW_INST *chip, >- int LockUnlock >+ int Lock > ) > { >- VGA_WR08(chip->PCIO, 0x3D4, 0x1F); >- VGA_WR08(chip->PCIO, 0x3D5, LockUnlock ? 0x99 : 0x57); >+ VGA_WR08(chip->PVIO, 0x3C4, 0x06); >+ VGA_WR08(chip->PVIO, 0x3C5, Lock ? 0x99 : 0x57); >+ vgaLockUnlock(chip, Lock); > } >-static void nv10LockUnlock >+static void nv4LockUnlock > ( > RIVA_HW_INST *chip, >- int LockUnlock >+ int Lock > ) > { > VGA_WR08(chip->PCIO, 0x3D4, 0x1F); >- VGA_WR08(chip->PCIO, 0x3D5, LockUnlock ? 0x99 : 0x57); >+ VGA_WR08(chip->PCIO, 0x3D5, Lock ? 0x99 : 0x57); >+ vgaLockUnlock(chip, Lock); > } > > static int ShowHideCursor >@@ -107,13 +118,13 @@ > int ShowHide > ) > { >- int current; >- current = chip->CurrentState->cursor1; >+ int cursor; >+ cursor = chip->CurrentState->cursor1; > chip->CurrentState->cursor1 = (chip->CurrentState->cursor1 & 0xFE) | >- (ShowHide & 0x01); >+ (ShowHide & 0x01); > VGA_WR08(chip->PCIO, 0x3D4, 0x31); > VGA_WR08(chip->PCIO, 0x3D5, chip->CurrentState->cursor1); >- return (current & 0x01); >+ return (cursor & 0x01); > } > > /****************************************************************************\ >@@ -604,7 +615,7 @@ > nv3_sim_state sim_data; > unsigned int M, N, P, pll, MClk; > >- pll = chip->PRAMDAC[0x00000504/4]; >+ pll = chip->PRAMDAC0[0x00000504/4]; > M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; > MClk = (N * chip->CrystalFreqKHz / M) >> P; > sim_data.pix_bpp = (char)pixelDepth; >@@ -791,10 +802,10 @@ > nv4_sim_state sim_data; > unsigned int M, N, P, pll, MClk, NVClk, cfg1; > >- pll = chip->PRAMDAC[0x00000504/4]; >+ pll = chip->PRAMDAC0[0x00000504/4]; > M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; > MClk = (N * chip->CrystalFreqKHz / M) >> P; >- pll = chip->PRAMDAC[0x00000500/4]; >+ pll = chip->PRAMDAC0[0x00000500/4]; > M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; > NVClk = (N * chip->CrystalFreqKHz / M) >> P; > cfg1 = chip->PFB[0x00000204/4]; >@@ -1052,10 +1063,10 @@ > nv10_sim_state sim_data; > unsigned int M, N, P, pll, MClk, NVClk, cfg1; > >- pll = chip->PRAMDAC[0x00000504/4]; >+ pll = chip->PRAMDAC0[0x00000504/4]; > M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; > MClk = (N * chip->CrystalFreqKHz / M) >> P; >- pll = chip->PRAMDAC[0x00000500/4]; >+ pll = chip->PRAMDAC0[0x00000500/4]; > M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; > NVClk = (N * chip->CrystalFreqKHz / M) >> P; > cfg1 = chip->PFB[0x00000204/4]; >@@ -1081,6 +1092,57 @@ > } > } > >+static void nForceUpdateArbitrationSettings >+( >+ unsigned VClk, >+ unsigned pixelDepth, >+ unsigned *burst, >+ unsigned *lwm, >+ RIVA_HW_INST *chip >+) >+{ >+ nv10_fifo_info fifo_data; >+ nv10_sim_state sim_data; >+ unsigned int M, N, P, pll, MClk, NVClk; >+ unsigned int uMClkPostDiv; >+ struct pci_dev *dev; >+ >+ dev = pci_find_slot(0, 3); >+ pci_read_config_dword(dev, 0x6C, &uMClkPostDiv); >+ uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf; >+ >+ if(!uMClkPostDiv) uMClkPostDiv = 4; >+ MClk = 400000 / uMClkPostDiv; >+ >+ pll = chip->PRAMDAC0[0x00000500/4]; >+ M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; >+ NVClk = (N * chip->CrystalFreqKHz / M) >> P; >+ sim_data.pix_bpp = (char)pixelDepth; >+ sim_data.enable_video = 0; >+ sim_data.enable_mp = 0; >+ >+ dev = pci_find_slot(0, 1); >+ pci_read_config_dword(dev, 0x7C, &sim_data.memory_type); >+ sim_data.memory_type = (sim_data.memory_type >> 12) & 1; >+ >+ sim_data.memory_width = 64; >+ sim_data.mem_latency = 3; >+ sim_data.mem_aligned = 1; >+ sim_data.mem_page_miss = 10; >+ sim_data.gr_during_vid = 0; >+ sim_data.pclk_khz = VClk; >+ sim_data.mclk_khz = MClk; >+ sim_data.nvclk_khz = NVClk; >+ nv10CalcArbitration(&fifo_data, &sim_data); >+ if (fifo_data.valid) >+ { >+ int b = fifo_data.graphics_burst_size >> 4; >+ *burst = 0; >+ while (b >>= 1) (*burst)++; >+ *lwm = fifo_data.graphics_lwm >> 3; >+ } >+} >+ > /****************************************************************************\ > * * > * RIVA Mode State Routines * >@@ -1093,7 +1155,6 @@ > static int CalcVClock > ( > int clockIn, >- int double_scan, > int *clockOut, > int *mOut, > int *nOut, >@@ -1109,18 +1170,16 @@ > DeltaOld = 0xFFFFFFFF; > > VClk = (unsigned)clockIn; >- if (double_scan) >- VClk *= 2; > >- if (chip->CrystalFreqKHz == 14318) >+ if (chip->CrystalFreqKHz == 13500) > { >- lowM = 8; >- highM = 14 - (chip->Architecture == NV_ARCH_03); >+ lowM = 7; >+ highM = 13 - (chip->Architecture == NV_ARCH_03); > } > else > { >- lowM = 7; >- highM = 13 - (chip->Architecture == NV_ARCH_03); >+ lowM = 8; >+ highM = 14 - (chip->Architecture == NV_ARCH_03); > } > > highP = 4 - (chip->Architecture == NV_ARCH_03); >@@ -1131,7 +1190,8 @@ > { > for (M = lowM; M <= highM; M++) > { >- N = (VClk * M / chip->CrystalFreqKHz) << P; >+ N = (VClk << P) * M / chip->CrystalFreqKHz; >+ if(N <= 255) { > Freq = (chip->CrystalFreqKHz * N / M) >> P; > if (Freq > VClk) > DeltaNew = Freq - VClk; >@@ -1148,6 +1208,7 @@ > } > } > } >+ } > return (DeltaOld != 0xFFFFFFFF); > } > /* >@@ -1161,15 +1222,7 @@ > int bpp, > int width, > int hDisplaySize, >- int hDisplay, >- int hStart, >- int hEnd, >- int hTotal, > int height, >- int vDisplay, >- int vStart, >- int vEnd, >- int vTotal, > int dotClock > ) > { >@@ -1177,15 +1230,14 @@ > /* > * Save mode parameters. > */ >- state->bpp = bpp; >+ state->bpp = bpp; /* this is not bitsPerPixel, it's 8,15,16,32 */ > state->width = width; > state->height = height; > /* > * Extended RIVA registers. > */ > pixelDepth = (bpp + 1)/8; >- CalcVClock(dotClock, hDisplaySize < 512, /* double scan? */ >- &VClk, &m, &n, &p, chip); >+ CalcVClock(dotClock, &VClk, &m, &n, &p, chip); > > switch (chip->Architecture) > { >@@ -1220,29 +1272,38 @@ > state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; > break; > case NV_ARCH_10: >- case NV_ARCH_20: >- nv10UpdateArbitrationSettings(VClk, >+ case NV_ARCH_20: >+ if((chip->Chipset == NV_CHIP_IGEFORCE2) || >+ (chip->Chipset == NV_CHIP_0x01F0)) >+ { >+ nForceUpdateArbitrationSettings(VClk, >+ pixelDepth * 8, >+ &(state->arbitration0), >+ &(state->arbitration1), >+ chip); >+ } else { >+ nv10UpdateArbitrationSettings(VClk, > pixelDepth * 8, > &(state->arbitration0), > &(state->arbitration1), > chip); >- state->cursor0 = 0x00; >- state->cursor1 = 0xFC; >- state->cursor2 = 0x00000000; >+ } >+ state->cursor0 = 0x80 | (chip->CursorStart >> 17); >+ state->cursor1 = (chip->CursorStart >> 11) << 2; >+ state->cursor2 = chip->CursorStart >> 24; > state->pllsel = 0x10000700; > state->config = chip->PFB[0x00000200/4]; > state->general = bpp == 16 ? 0x00101100 : 0x00100100; > state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; > break; > } >+ >+ /* Paul Richards: below if block borks things in kernel for some reason */ >+ /* if((bpp != 8) && (chip->Architecture != NV_ARCH_03)) >+ state->general |= 0x00000030; */ >+ > state->vpll = (p << 16) | (n << 8) | m; >- state->screen = ((hTotal & 0x040) >> 2) >- | ((vDisplay & 0x400) >> 7) >- | ((vStart & 0x400) >> 8) >- | ((vDisplay & 0x400) >> 9) >- | ((vTotal & 0x400) >> 10); > state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3; >- state->horiz = hTotal < 260 ? 0x00 : 0x01; > state->pixel = pixelDepth > 2 ? 3 : pixelDepth; > state->offset0 = > state->offset1 = >@@ -1286,7 +1347,7 @@ > chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); > break; > case NV_ARCH_10: >- case NV_ARCH_20: >+ case NV_ARCH_20: > /* > * Initialize state for the RivaTriangle3D05 routines. > */ >@@ -1395,7 +1456,13 @@ > chip->PGRAPH[0x0000067C/4] = state->pitch3; > break; > case NV_ARCH_10: >- case NV_ARCH_20: >+ case NV_ARCH_20: >+ if(chip->twoHeads) { >+ VGA_WR08(chip->PCIO, 0x03D4, 0x44); >+ VGA_WR08(chip->PCIO, 0x03D5, state->crtcOwner); >+ chip->LockUnlock(chip, 0); >+ } >+ > LOAD_FIXED_STATE(nv10,PFIFO); > LOAD_FIXED_STATE(nv10,PRAMIN); > LOAD_FIXED_STATE(nv10,PGRAPH); >@@ -1425,39 +1492,52 @@ > break; > } > >- if (chip->Architecture == NV_ARCH_10) { >- chip->PGRAPH[0x00000640/4] = state->offset0; >- chip->PGRAPH[0x00000644/4] = state->offset1; >- chip->PGRAPH[0x00000648/4] = state->offset2; >- chip->PGRAPH[0x0000064C/4] = state->offset3; >- chip->PGRAPH[0x00000670/4] = state->pitch0; >- chip->PGRAPH[0x00000674/4] = state->pitch1; >- chip->PGRAPH[0x00000678/4] = state->pitch2; >- chip->PGRAPH[0x0000067C/4] = state->pitch3; >- chip->PGRAPH[0x00000680/4] = state->pitch3; >- } else { >- chip->PGRAPH[0x00000820/4] = state->offset0; >- chip->PGRAPH[0x00000824/4] = state->offset1; >- chip->PGRAPH[0x00000828/4] = state->offset2; >- chip->PGRAPH[0x0000082C/4] = state->offset3; >- chip->PGRAPH[0x00000850/4] = state->pitch0; >- chip->PGRAPH[0x00000854/4] = state->pitch1; >- chip->PGRAPH[0x00000858/4] = state->pitch2; >- chip->PGRAPH[0x0000085C/4] = state->pitch3; >- chip->PGRAPH[0x00000860/4] = state->pitch3; >- chip->PGRAPH[0x00000864/4] = state->pitch3; >- chip->PGRAPH[0x000009A4/4] = chip->PFB[0x00000200/4]; >- chip->PGRAPH[0x000009A8/4] = chip->PFB[0x00000204/4]; >- } >- >- chip->PFB[0x00000240/4] = 0; >- chip->PFB[0x00000244/4] = 0; >- chip->PFB[0x00000248/4] = 0; >- chip->PFB[0x0000024C/4] = 0; >- chip->PFB[0x00000250/4] = 0; >- chip->PFB[0x00000244/4] = 0; >- chip->PFB[0x00000248/4] = 0; >- chip->PFB[0x0000024C/4] = 0; >+ if(chip->Architecture == NV_ARCH_10) { >+ chip->PGRAPH[0x00000640/4] = state->offset0; >+ chip->PGRAPH[0x00000644/4] = state->offset1; >+ chip->PGRAPH[0x00000648/4] = state->offset2; >+ chip->PGRAPH[0x0000064C/4] = state->offset3; >+ chip->PGRAPH[0x00000670/4] = state->pitch0; >+ chip->PGRAPH[0x00000674/4] = state->pitch1; >+ chip->PGRAPH[0x00000678/4] = state->pitch2; >+ chip->PGRAPH[0x0000067C/4] = state->pitch3; >+ chip->PGRAPH[0x00000680/4] = state->pitch3; >+ } else { >+ chip->PGRAPH[0x00000820/4] = state->offset0; >+ chip->PGRAPH[0x00000824/4] = state->offset1; >+ chip->PGRAPH[0x00000828/4] = state->offset2; >+ chip->PGRAPH[0x0000082C/4] = state->offset3; >+ chip->PGRAPH[0x00000850/4] = state->pitch0; >+ chip->PGRAPH[0x00000854/4] = state->pitch1; >+ chip->PGRAPH[0x00000858/4] = state->pitch2; >+ chip->PGRAPH[0x0000085C/4] = state->pitch3; >+ chip->PGRAPH[0x00000860/4] = state->pitch3; >+ chip->PGRAPH[0x00000864/4] = state->pitch3; >+ chip->PGRAPH[0x000009A4/4] = chip->PFB[0x00000200/4]; >+ chip->PGRAPH[0x000009A8/4] = chip->PFB[0x00000204/4]; >+ } >+ if(chip->twoHeads) { >+ chip->PCRTC0[0x00000860/4] = state->head; >+ chip->PCRTC0[0x00002860/4] = state->head2; >+ } >+ chip->PRAMDAC[0x00000404/4] |= (1 << 25); >+ >+ chip->PMC[0x00008704/4] = 1; >+ chip->PMC[0x00008140/4] = 0; >+ chip->PMC[0x00008920/4] = 0; >+ chip->PMC[0x00008924/4] = 0; >+ chip->PMC[0x00008908/4] = 0x01ffffff; >+ chip->PMC[0x0000890C/4] = 0x01ffffff; >+ chip->PMC[0x00001588/4] = 0; >+ >+ chip->PFB[0x00000240/4] = 0; >+ chip->PFB[0x00000244/4] = 0; >+ chip->PFB[0x00000248/4] = 0; >+ chip->PFB[0x0000024C/4] = 0; >+ chip->PFB[0x00000250/4] = 0; >+ chip->PFB[0x00000254/4] = 0; >+ chip->PFB[0x00000258/4] = 0; >+ chip->PFB[0x0000025C/4] = 0; > > chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4]; > chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4]; >@@ -1533,15 +1613,26 @@ > for (i = 0; i < 4; i++) > chip->PGRAPH[0x00000F54/4] = 0x00000000; > >- if (chip->flatPanel) { >- VGA_WR08(chip->PCIO, 0x3d4, 0x53); >- VGA_WR08(chip->PCIO, 0x3d5, 0); >- VGA_WR08(chip->PCIO, 0x3d4, 0x54); >- VGA_WR08(chip->PCIO, 0x3d5, 0); >- VGA_WR08(chip->PCIO, 0x3d4, 0x21); >- VGA_WR08(chip->PCIO, 0x3d5, 0xfa); >- } >- break; >+ chip->PCRTC[0x00000810/4] = state->cursorConfig; >+ >+ if(chip->flatPanel) { >+ if((chip->Chipset & 0x0ff0) == 0x0110) { >+ chip->PRAMDAC[0x0528/4] = state->dither; >+ } else >+ if((chip->Chipset & 0x0ff0) >= 0x0170) { >+ chip->PRAMDAC[0x083C/4] = state->dither; >+ } >+ >+ VGA_WR08(chip->PCIO, 0x03D4, 0x53); >+ VGA_WR08(chip->PCIO, 0x03D5, 0); >+ VGA_WR08(chip->PCIO, 0x03D4, 0x54); >+ VGA_WR08(chip->PCIO, 0x03D5, 0); >+ VGA_WR08(chip->PCIO, 0x03D4, 0x21); >+ VGA_WR08(chip->PCIO, 0x03D5, 0xfa); >+ } >+ >+ VGA_WR08(chip->PCIO, 0x03D4, 0x41); >+ VGA_WR08(chip->PCIO, 0x03D5, state->extra); > } > LOAD_FIXED_STATE(Riva,FIFO); > UpdateFifoState(chip); >@@ -1566,25 +1657,26 @@ > VGA_WR08(chip->PCIO, 0x03D5, state->cursor0); > VGA_WR08(chip->PCIO, 0x03D4, 0x31); > VGA_WR08(chip->PCIO, 0x03D5, state->cursor1); >- VGA_WR08(chip->PCIO, 0x03D4, 0x41); >- VGA_WR08(chip->PCIO, 0x03D5, state->extra); >- >- if (!chip->flatPanel) { >- chip->PRAMDAC[0x00000508/4] = state->vpll; >- chip->PRAMDAC[0x00000520/4] = state->vpll2; >- chip->PRAMDAC[0x0000050C/4] = state->pllsel; >- } else { >- chip->PRAMDAC[0x00000848/4] = state->scale; >- } >- chip->PRAMDAC[0x00000300/4] = state->cursor2; >- chip->PRAMDAC[0x00000508/4] = state->vpll; >- chip->PRAMDAC[0x0000050C/4] = state->pllsel; >+ VGA_WR08(chip->PCIO, 0x03D4, 0x2F); >+ VGA_WR08(chip->PCIO, 0x03D5, state->cursor2); >+ VGA_WR08(chip->PCIO, 0x03D4, 0x39); >+ VGA_WR08(chip->PCIO, 0x03D5, state->interlace); >+ >+ if(!chip->flatPanel) { >+ chip->PRAMDAC0[0x00000508/4] = state->vpll; >+ chip->PRAMDAC0[0x0000050C/4] = state->pllsel; >+ if(chip->twoHeads) >+ chip->PRAMDAC0[0x00000520/4] = state->vpll2; >+ } else { >+ chip->PRAMDAC[0x00000848/4] = state->scale; >+ } > chip->PRAMDAC[0x00000600/4] = state->general; >+ > /* > * Turn off VBlank enable and reset. > */ >- *(chip->VBLANKENABLE) = 0; >- *(chip->VBLANK) = chip->VBlankBit; >+ chip->PCRTC[0x00000140/4] = 0; >+ chip->PCRTC[0x00000100/4] = chip->VBlankBit; > /* > * Set interrupt enable. > */ >@@ -1627,14 +1719,15 @@ > state->cursor0 = VGA_RD08(chip->PCIO, 0x03D5); > VGA_WR08(chip->PCIO, 0x03D4, 0x31); > state->cursor1 = VGA_RD08(chip->PCIO, 0x03D5); >- VGA_WR08(chip->PCIO, 0x03D4, 0x41); >- state->extra = VGA_RD08(chip->PCIO, 0x03D5); >- state->cursor2 = chip->PRAMDAC[0x00000300/4]; >- state->vpll = chip->PRAMDAC[0x00000508/4]; >- state->vpll2 = chip->PRAMDAC[0x00000520/4]; >- state->pllsel = chip->PRAMDAC[0x0000050C/4]; >+ VGA_WR08(chip->PCIO, 0x03D4, 0x2F); >+ state->cursor2 = VGA_RD08(chip->PCIO, 0x03D5); >+ VGA_WR08(chip->PCIO, 0x03D4, 0x39); >+ state->interlace = VGA_RD08(chip->PCIO, 0x03D5); >+ state->vpll = chip->PRAMDAC0[0x00000508/4]; >+ state->vpll2 = chip->PRAMDAC0[0x00000520/4]; >+ state->pllsel = chip->PRAMDAC0[0x0000050C/4]; > state->general = chip->PRAMDAC[0x00000600/4]; >- state->scale = chip->PRAMDAC[0x00000848/4]; >+ state->scale = chip->PRAMDAC[0x00000848/4]; > state->config = chip->PFB[0x00000200/4]; > switch (chip->Architecture) > { >@@ -1659,7 +1752,7 @@ > state->pitch3 = chip->PGRAPH[0x0000067C/4]; > break; > case NV_ARCH_10: >- case NV_ARCH_20: >+ case NV_ARCH_20: > state->offset0 = chip->PGRAPH[0x00000640/4]; > state->offset1 = chip->PGRAPH[0x00000644/4]; > state->offset2 = chip->PGRAPH[0x00000648/4]; >@@ -1668,6 +1761,22 @@ > state->pitch1 = chip->PGRAPH[0x00000674/4]; > state->pitch2 = chip->PGRAPH[0x00000678/4]; > state->pitch3 = chip->PGRAPH[0x0000067C/4]; >+ if(chip->twoHeads) { >+ state->head = chip->PCRTC0[0x00000860/4]; >+ state->head2 = chip->PCRTC0[0x00002860/4]; >+ VGA_WR08(chip->PCIO, 0x03D4, 0x44); >+ state->crtcOwner = VGA_RD08(chip->PCIO, 0x03D5); >+ } >+ VGA_WR08(chip->PCIO, 0x03D4, 0x41); >+ state->extra = VGA_RD08(chip->PCIO, 0x03D5); >+ state->cursorConfig = chip->PCRTC[0x00000810/4]; >+ >+ if((chip->Chipset & 0x0ff0) == 0x0110) { >+ state->dither = chip->PRAMDAC[0x0528/4]; >+ } else >+ if((chip->Chipset & 0x0ff0) >= 0x0170) { >+ state->dither = chip->PRAMDAC[0x083C/4]; >+ } > break; > } > } >@@ -1677,6 +1786,15 @@ > unsigned start > ) > { >+ chip->PCRTC[0x800/4] = start; >+} >+ >+static void SetStartAddress3 >+( >+ RIVA_HW_INST *chip, >+ unsigned start >+) >+{ > int offset = start >> 2; > int pan = (start & 3) << 1; > unsigned char tmp; >@@ -1857,11 +1975,8 @@ > break; > } > } >- chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000020) ? 14318 : 13500; >+ chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500; > chip->CURSOR = &(chip->PRAMIN[0x00008000/4 - 0x0800/4]); >- chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]); >- chip->VBLANKENABLE = &(chip->PGRAPH[0x0140/4]); >- chip->VBLANK = &(chip->PGRAPH[0x0100/4]); > chip->VBlankBit = 0x00000100; > chip->MaxVClockFreqKHz = 256000; > /* >@@ -1872,7 +1987,7 @@ > chip->CalcStateExt = CalcStateExt; > chip->LoadStateExt = LoadStateExt; > chip->UnloadStateExt = UnloadStateExt; >- chip->SetStartAddress = SetStartAddress; >+ chip->SetStartAddress = SetStartAddress3; > chip->SetSurfaces2D = nv3SetSurfaces2D; > chip->SetSurfaces3D = nv3SetSurfaces3D; > chip->LockUnlock = nv3LockUnlock; >@@ -1920,9 +2035,6 @@ > } > chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500; > chip->CURSOR = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]); >- chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]); >- chip->VBLANKENABLE = &(chip->PCRTC[0x0140/4]); >- chip->VBLANK = &(chip->PCRTC[0x0100/4]); > chip->VBlankBit = 0x00000001; > chip->MaxVClockFreqKHz = 350000; > /* >@@ -1940,41 +2052,58 @@ > } > static void nv10GetConfig > ( >- RIVA_HW_INST *chip >+ RIVA_HW_INST *chip, >+ unsigned int chipset > ) > { >-#if defined(__BIG_ENDIAN) >- chip->PMC[0x00000004/4] = 0x01000001; >+ struct pci_dev* dev; >+ int amt; >+ >+#ifdef __BIG_ENDIAN >+ /* turn on big endian register access */ >+ if(!(chip->PMC[0x00000004/4] & 0x01000001)) >+ chip->PMC[0x00000004/4] = 0x01000001; > #endif >+ > /* > * Fill in chip configuration. > */ >- switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) >- { >- case 0x02: >- chip->RamAmountKBytes = 1024 * 2; >- break; >- case 0x04: >- chip->RamAmountKBytes = 1024 * 4; >- break; >- case 0x08: >- chip->RamAmountKBytes = 1024 * 8; >- break; >- case 0x10: >- chip->RamAmountKBytes = 1024 * 16; >- break; >- case 0x20: >- chip->RamAmountKBytes = 1024 * 32; >- break; >- case 0x40: >- chip->RamAmountKBytes = 1024 * 64; >- break; >- case 0x80: >- chip->RamAmountKBytes = 1024 * 128; >- break; >- default: >- chip->RamAmountKBytes = 1024 * 16; >- break; >+ if(chipset == NV_CHIP_IGEFORCE2) { >+ dev = pci_find_slot(0, 1); >+ pci_read_config_dword(dev, 0x7C, &amt); >+ chip->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; >+ } else if(chipset == NV_CHIP_0x01F0) { >+ dev = pci_find_slot(0, 1); >+ pci_read_config_dword(dev, 0x84, &amt); >+ chip->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; >+ } else { >+ switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) >+ { >+ case 0x02: >+ chip->RamAmountKBytes = 1024 * 2; >+ break; >+ case 0x04: >+ chip->RamAmountKBytes = 1024 * 4; >+ break; >+ case 0x08: >+ chip->RamAmountKBytes = 1024 * 8; >+ break; >+ case 0x10: >+ chip->RamAmountKBytes = 1024 * 16; >+ break; >+ case 0x20: >+ chip->RamAmountKBytes = 1024 * 32; >+ break; >+ case 0x40: >+ chip->RamAmountKBytes = 1024 * 64; >+ break; >+ case 0x80: >+ chip->RamAmountKBytes = 1024 * 128; >+ break; >+ default: >+ chip->RamAmountKBytes = 1024 * 16; >+ break; >+ } > } > switch ((chip->PFB[0x00000000/4] >> 3) & 0x00000003) > { >@@ -1985,11 +2114,29 @@ > chip->RamBandwidthKBytesPerSec = 1000000; > break; > } >- chip->CrystalFreqKHz = (chip->PEXTDEV[0x00000000/4] & 0x00000040) ? 14318 : 13500; >- chip->CURSOR = &(chip->PRAMIN[0x00010000/4 - 0x0800/4]); >- chip->CURSORPOS = &(chip->PRAMDAC[0x0300/4]); >- chip->VBLANKENABLE = &(chip->PCRTC[0x0140/4]); >- chip->VBLANK = &(chip->PCRTC[0x0100/4]); >+ chip->CrystalFreqKHz = (chip->PEXTDEV[0x0000/4] & (1 << 6)) ? 14318 : >+ 13500; >+ >+ switch (chipset & 0x0ff0) { >+ case 0x0170: >+ case 0x0180: >+ case 0x01F0: >+ case 0x0250: >+ case 0x0280: >+ case 0x0300: >+ case 0x0310: >+ case 0x0320: >+ case 0x0330: >+ case 0x0340: >+ if(chip->PEXTDEV[0x0000/4] & (1 << 22)) >+ chip->CrystalFreqKHz = 27000; >+ break; >+ default: >+ break; >+ } >+ >+ chip->CursorStart = (chip->RamAmountKBytes - 128) * 1024; >+ chip->CURSOR = NULL; /* can't set this here */ > chip->VBlankBit = 0x00000001; > chip->MaxVClockFreqKHz = 350000; > /* >@@ -2003,11 +2150,31 @@ > chip->SetStartAddress = SetStartAddress; > chip->SetSurfaces2D = nv10SetSurfaces2D; > chip->SetSurfaces3D = nv10SetSurfaces3D; >- chip->LockUnlock = nv10LockUnlock; >+ chip->LockUnlock = nv4LockUnlock; >+ >+ switch(chipset & 0x0ff0) { >+ case 0x0110: >+ case 0x0170: >+ case 0x0180: >+ case 0x01F0: >+ case 0x0250: >+ case 0x0280: >+ case 0x0300: >+ case 0x0310: >+ case 0x0320: >+ case 0x0330: >+ case 0x0340: >+ chip->twoHeads = TRUE; >+ break; >+ default: >+ chip->twoHeads = FALSE; >+ break; >+ } > } > int RivaGetConfig > ( >- RIVA_HW_INST *chip >+ RIVA_HW_INST *chip, >+ unsigned int chipset > ) > { > /* >@@ -2026,12 +2193,13 @@ > nv4GetConfig(chip); > break; > case NV_ARCH_10: >- case NV_ARCH_20: >- nv10GetConfig(chip); >+ case NV_ARCH_20: >+ nv10GetConfig(chip, chipset); > break; > default: > return (-1); > } >+ chip->Chipset = chipset; > /* > * Fill in FIFO pointers. > */ >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/riva_hw.h linux-2.4.22-ppc-dev/drivers/video/riva/riva_hw.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/riva_hw.h 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/riva_hw.h 2003-08-25 23:37:29.000000000 +0200 >@@ -41,14 +41,28 @@ > * GPL licensing note -- nVidia is allowing a liberal interpretation of > * the documentation restriction above, to merely say that this nVidia's > * copyright and disclaimer should be included with all code derived >- * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 >+ * from this source. -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 > */ > >-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.6 2000/02/08 17:19:12 dawes Exp $ */ >+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.21 2002/10/14 18:22:46 mvojkovi Exp $ */ > #ifndef __RIVA_HW_H__ > #define __RIVA_HW_H__ > #define RIVA_SW_VERSION 0x00010003 > >+#ifndef Bool >+typedef int Bool; >+#endif >+ >+#ifndef TRUE >+#define TRUE 1 >+#endif >+#ifndef FALSE >+#define FALSE 0 >+#endif >+#ifndef NULL >+#define NULL 0 >+#endif >+ > /* > * Typedefs to force certain sized values. > */ >@@ -99,7 +113,7 @@ > #else > U016 FifoFree; > U016 Nop; >-#endif >+#endif > U032 reserved01[0x0BB]; > U032 Rop3; > } RivaRop; >@@ -269,7 +283,7 @@ > #else > U016 FifoFree; > U016 Nop; >-#endif >+#endif > U032 reserved01[0x0BC]; > U032 TextureOffset; > U032 TextureFormat; >@@ -299,7 +313,7 @@ > #else > U016 FifoFree; > U016 Nop; >-#endif >+#endif > U032 reserved01[0x0BB]; > U032 ColorKey; > U032 TextureOffset; >@@ -337,7 +351,7 @@ > #else > U016 FifoFree; > U016 Nop[1]; >-#endif >+#endif > U032 reserved01[0x0BC]; > U032 Color; /* source color 0304-0307*/ > U032 Reserved02[0x03e]; >@@ -397,6 +411,9 @@ > * * > \***************************************************************************/ > >+#define FP_ENABLE 1 >+#define FP_DITHER 2 >+ > struct _riva_hw_inst; > struct _riva_hw_state; > /* >@@ -409,6 +426,7 @@ > */ > U032 Architecture; > U032 Version; >+ U032 Chipset; > U032 CrystalFreqKHz; > U032 RamAmountKBytes; > U032 MaxVClockFreqKHz; >@@ -418,12 +436,15 @@ > U032 VBlankBit; > U032 FifoFreeCount; > U032 FifoEmptyCount; >+ U032 CursorStart; > U032 flatPanel; >+ Bool twoHeads; > /* > * Non-FIFO registers. > */ >+ volatile U032 *PCRTC0; > volatile U032 *PCRTC; >- volatile U032 *PRAMDAC; >+ volatile U032 *PRAMDAC0; > volatile U032 *PFB; > volatile U032 *PFIFO; > volatile U032 *PGRAPH; >@@ -433,17 +454,17 @@ > volatile U032 *PRAMIN; > volatile U032 *FIFO; > volatile U032 *CURSOR; >- volatile U032 *CURSORPOS; >- volatile U032 *VBLANKENABLE; >- volatile U032 *VBLANK; >+ volatile U008 *PCIO0; > volatile U008 *PCIO; > volatile U008 *PVIO; >+ volatile U008 *PDIO0; > volatile U008 *PDIO; >+ volatile U032 *PRAMDAC; > /* > * Common chip functions. > */ > int (*Busy)(struct _riva_hw_inst *); >- void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int,int,int,int,int,int,int,int,int); >+ void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int); > void (*LoadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *); > void (*UnloadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *); > void (*SetStartAddress)(struct _riva_hw_inst *,U032); >@@ -476,10 +497,12 @@ > U032 bpp; > U032 width; > U032 height; >+ U032 interlace; > U032 repaint0; > U032 repaint1; > U032 screen; > U032 scale; >+ U032 dither; > U032 extra; > U032 pixel; > U032 horiz; >@@ -489,7 +512,11 @@ > U032 vpll2; > U032 pllsel; > U032 general; >+ U032 crtcOwner; >+ U032 head; >+ U032 head2; > U032 config; >+ U032 cursorConfig; > U032 cursor0; > U032 cursor1; > U032 cursor2; >@@ -505,16 +532,24 @@ > /* > * External routines. > */ >-int RivaGetConfig(RIVA_HW_INST *); >+int RivaGetConfig(RIVA_HW_INST *, unsigned int); > /* > * FIFO Free Count. Should attempt to yield processor if RIVA is busy. > */ > >-#define RIVA_FIFO_FREE(hwinst,hwptr,cnt) \ >-{ \ >- while ((hwinst).FifoFreeCount < (cnt)) \ >- (hwinst).FifoFreeCount = (hwinst).hwptr->FifoFree >> 2; \ >- (hwinst).FifoFreeCount -= (cnt); \ >+/* >+ * The mb()'s work around some lockup problems I experienced with some >+ * GeForceII MX cards, neither I nor Mark Vojkovich knows for sure what's >+ * going on there. --BenH >+ */ >+#define RIVA_FIFO_FREE(hwinst,hwptr,cnt) \ >+{ \ >+ while ((hwinst).FifoFreeCount < (cnt)) { \ >+ mb(); \ >+ mb(); \ >+ (hwinst).FifoFreeCount = (hwinst).hwptr->FifoFree >> 2; \ >+ } \ >+ (hwinst).FifoFreeCount -= (cnt); \ > } > #endif /* __RIVA_HW_H__ */ > >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/riva_tbl.h linux-2.4.22-ppc-dev/drivers/video/riva/riva_tbl.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/riva_tbl.h 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/riva_tbl.h 2003-08-25 23:37:26.000000000 +0200 >@@ -41,10 +41,12 @@ > * GPL licensing note -- nVidia is allowing a liberal interpretation of > * the documentation restriction above, to merely say that this nVidia's > * copyright and disclaimer should be included with all code derived >- * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 >+ * from this source. -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 > */ > >-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.5 2000/02/08 17:19:12 dawes Exp $ */ >+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.9 2002/01/30 01:35:03 mvojkovi Exp $ */ >+ >+ > /* > * RIVA Fixed Functionality Init Tables. > */ >@@ -69,6 +71,7 @@ > {0x00001800, 0x80000010}, > {0x00002000, 0x80000011}, > {0x00002800, 0x80000012}, >+ {0x00003000, 0x80000016}, > {0x00003800, 0x80000013} > }; > static unsigned nv3TablePFIFO[][2] = >@@ -174,6 +177,8 @@ > {0x00000249, 0x00CC0346}, > {0x0000024C, 0x80000013}, > {0x0000024D, 0x00D70347}, >+ {0x00000258, 0x80000016}, >+ {0x00000259, 0x00CA034C}, > {0x00000D05, 0x00000000}, > {0x00000D06, 0x00000000}, > {0x00000D07, 0x00000000}, >@@ -210,7 +215,10 @@ > {0x00000D2C, 0x10830200}, > {0x00000D2D, 0x00000000}, > {0x00000D2E, 0x00000000}, >- {0x00000D2F, 0x00000000} >+ {0x00000D2F, 0x00000000}, >+ {0x00000D31, 0x00000000}, >+ {0x00000D32, 0x00000000}, >+ {0x00000D33, 0x00000000} > }; > static unsigned nv3TablePRAMIN_8BPP[][2] = > { >@@ -222,7 +230,8 @@ > {0x00000D10, 0x10118203}, > {0x00000D14, 0x10110203}, > {0x00000D18, 0x10110203}, >- {0x00000D1C, 0x10419208} >+ {0x00000D1C, 0x10419208}, >+ {0x00000D30, 0x10118203} > }; > static unsigned nv3TablePRAMIN_15BPP[][2] = > { >@@ -234,7 +243,8 @@ > {0x00000D10, 0x10118200}, > {0x00000D14, 0x10110200}, > {0x00000D18, 0x10110200}, >- {0x00000D1C, 0x10419208} >+ {0x00000D1C, 0x10419208}, >+ {0x00000D30, 0x10118200} > }; > static unsigned nv3TablePRAMIN_32BPP[][2] = > { >@@ -246,7 +256,8 @@ > {0x00000D10, 0x10118201}, > {0x00000D14, 0x10110201}, > {0x00000D18, 0x10110201}, >- {0x00000D1C, 0x10419208} >+ {0x00000D1C, 0x10419208}, >+ {0x00000D30, 0x10118201} > }; > static unsigned nv4TableFIFO[][2] = > { >@@ -370,6 +381,8 @@ > {0x00000009, 0x80011149}, > {0x0000000A, 0x80000015}, > {0x0000000B, 0x8001114A}, >+ {0x0000000C, 0x80000016}, >+ {0x0000000D, 0x8001114F}, > {0x00000020, 0x80000000}, > {0x00000021, 0x80011142}, > {0x00000022, 0x80000001}, >@@ -437,7 +450,10 @@ > {0x00000537, 0x00000000}, > {0x00000538, 0x0000005B}, > {0x0000053A, 0x11401140}, >- {0x0000053B, 0x00000000} >+ {0x0000053B, 0x00000000}, >+ {0x0000053C, 0x0300A01C}, >+ {0x0000053E, 0x11401140}, >+ {0x0000053F, 0x00000000} > }; > static unsigned nv4TablePRAMIN_8BPP[][2] = > { >@@ -452,7 +468,8 @@ > {0x0000052D, 0x00000302}, > {0x0000052E, 0x00000302}, > {0x00000535, 0x00000000}, >- {0x00000539, 0x00000000} >+ {0x00000539, 0x00000000}, >+ {0x0000053D, 0x00000302} > }; > static unsigned nv4TablePRAMIN_15BPP[][2] = > { >@@ -467,7 +484,8 @@ > {0x0000052D, 0x00000902}, > {0x0000052E, 0x00000902}, > {0x00000535, 0x00000702}, >- {0x00000539, 0x00000702} >+ {0x00000539, 0x00000702}, >+ {0x0000053D, 0x00000902} > }; > static unsigned nv4TablePRAMIN_16BPP[][2] = > { >@@ -482,7 +500,8 @@ > {0x0000052D, 0x00000C02}, > {0x0000052E, 0x00000C02}, > {0x00000535, 0x00000702}, >- {0x00000539, 0x00000702} >+ {0x00000539, 0x00000702}, >+ {0x0000053D, 0x00000C02} > }; > static unsigned nv4TablePRAMIN_32BPP[][2] = > { >@@ -497,7 +516,8 @@ > {0x0000052D, 0x00000E02}, > {0x0000052E, 0x00000E02}, > {0x00000535, 0x00000E02}, >- {0x00000539, 0x00000E02} >+ {0x00000539, 0x00000E02}, >+ {0x0000053D, 0x00000E02} > }; > static unsigned nv10TableFIFO[][2] = > { >@@ -810,6 +830,8 @@ > {0x00000009, 0x80011149}, > {0x0000000A, 0x80000015}, > {0x0000000B, 0x8001114A}, >+ {0x0000000C, 0x80000016}, >+ {0x0000000D, 0x80011150}, > {0x00000020, 0x80000000}, > {0x00000021, 0x80011142}, > {0x00000022, 0x80000001}, >@@ -831,7 +853,7 @@ > {0x00000502, 0x00000002}, > {0x00000503, 0x00000002}, > #ifdef __BIG_ENDIAN >- {0x00000508, 0x01088043}, >+ {0x00000508, 0x01088043}, > #else > {0x00000508, 0x01008043}, > #endif >@@ -946,7 +968,7 @@ > {0x0000052E, 0x00000902}, > {0x00000535, 0x00000902}, > {0x00000539, 0x00000902}, >- {0x0000053D, 0x00000902}, >+ {0x0000053D, 0x00000902}, > {0x00000541, 0x00000902} > }; > static unsigned nv10TablePRAMIN_16BPP[][2] = >diff -Naur linux-2.4.22-ppc-dev.orig/drivers/video/riva/rivafb.h linux-2.4.22-ppc-dev/drivers/video/riva/rivafb.h >--- linux-2.4.22-ppc-dev.orig/drivers/video/riva/rivafb.h 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/drivers/video/riva/rivafb.h 2003-08-25 23:37:53.000000000 +0200 >@@ -92,6 +92,12 @@ > #ifdef CONFIG_MTRR > struct { int vram; int vram_valid; } mtrr; > #endif >+ unsigned int Chipset; >+ int forceCRTC; >+ Bool SecondCRTC; >+ int FlatPanel; > }; > >+void riva_common_setup(struct rivafb_info*); >+ > #endif /* __RIVAFB_H */ >diff -Naur linux-2.4.22-ppc-dev.orig/fs/buffer.c linux-2.4.22-ppc-dev/fs/buffer.c >--- linux-2.4.22-ppc-dev.orig/fs/buffer.c 2003-08-27 15:18:03.000000000 +0200 >+++ linux-2.4.22-ppc-dev/fs/buffer.c 2003-08-25 23:37:36.000000000 +0200 >@@ -88,6 +88,13 @@ > static int osync_buffers_list(struct list_head *); > static void __refile_buffer(struct buffer_head *); > >+/* >+ * A global sysctl-controlled flag which puts the machine into "laptop mode" >+ */ >+int laptop_mode; >+ >+static DECLARE_WAIT_QUEUE_HEAD(kupdate_wait); >+ > /* This is used by some architectures to estimate available memory. */ > atomic_t buffermem_pages = ATOMIC_INIT(0); > >@@ -1016,7 +1023,7 @@ > dirty *= 100; > dirty_limit = tot * bdf_prm.b_un.nfract_stop_bdflush; > >- if (dirty > dirty_limit) >+ if (!laptop_mode && dirty > dirty_limit) > return 0; > return 1; > } >@@ -1066,6 +1073,8 @@ > void mark_buffer_dirty(struct buffer_head *bh) > { > if (!atomic_set_buffer_dirty(bh)) { >+ if (block_dump) >+ printk("%s: dirtied buffer\n", current->comm); > __mark_dirty(bh); > balance_dirty(); > } >@@ -1077,6 +1086,13 @@ > } > EXPORT_SYMBOL(set_buffer_flushtime); > >+unsigned long get_buffer_flushtime(void) >+{ >+ return bdf_prm.b_un.age_buffer; >+} >+EXPORT_SYMBOL(get_buffer_flushtime); >+ >+ > /* > * A buffer may need to be moved from one buffer list to another > * (e.g. in case it is not shared any more). Handle this. >@@ -2859,6 +2875,12 @@ > wake_up_interruptible(&bdflush_wait); > } > >+void wakeup_kupdate(void) >+{ >+ if (waitqueue_active(&kupdate_wait)) >+ wake_up(&kupdate_wait); >+} >+ > /* > * Here we attempt to write back old buffers. We also try to flush inodes > * and supers as well, since this function is essentially "update", and >@@ -2879,7 +2901,9 @@ > > spin_lock(&lru_list_lock); > bh = lru_list[BUF_DIRTY]; >- if (!bh || time_before(jiffies, bh->b_flushtime)) >+ if (!bh) >+ break; >+ if (time_before(jiffies, bh->b_flushtime) && !laptop_mode) > break; > if (write_some_buffers(NODEV)) > continue; >@@ -3027,16 +3051,20 @@ > complete((struct completion *)startup); > > for (;;) { >+ DECLARE_WAITQUEUE(wait, tsk); >+ >+ add_wait_queue(&kupdate_wait, &wait); >+ > /* update interval */ > interval = bdf_prm.b_un.interval; > if (interval) { > tsk->state = TASK_INTERRUPTIBLE; > schedule_timeout(interval); > } else { >- stop_kupdate: > tsk->state = TASK_STOPPED; > schedule(); /* wait for SIGCONT */ > } >+ remove_wait_queue(&kupdate_wait, &wait); > /* check for sigstop */ > if (signal_pending(tsk)) { > int stopped = 0; >@@ -3047,13 +3075,17 @@ > } > recalc_sigpending(tsk); > spin_unlock_irq(&tsk->sigmask_lock); >- if (stopped) >- goto stop_kupdate; >+ if (stopped) { >+ tsk->state = TASK_STOPPED; >+ schedule(); /* wait for SIGCONT */ >+ } > } > #ifdef DEBUG > printk(KERN_DEBUG "kupdate() activated...\n"); > #endif > sync_old_buffers(); >+ if (laptop_mode) >+ fsync_dev(NODEV); > run_task_queue(&tq_disk); > } > } >diff -Naur linux-2.4.22-ppc-dev.orig/fs/hfsplus/hfsplus_fs.h linux-2.4.22-ppc-dev/fs/hfsplus/hfsplus_fs.h >--- linux-2.4.22-ppc-dev.orig/fs/hfsplus/hfsplus_fs.h 2003-08-27 15:18:03.000000000 +0200 >+++ linux-2.4.22-ppc-dev/fs/hfsplus/hfsplus_fs.h 2003-08-25 23:37:27.000000000 +0200 >@@ -211,6 +211,7 @@ > hfsplus_cat_key key; > }; > >+ > #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) > typedef long sector_t; > #endif >diff -Naur linux-2.4.22-ppc-dev.orig/fs/jbd/transaction.c linux-2.4.22-ppc-dev/fs/jbd/transaction.c >--- linux-2.4.22-ppc-dev.orig/fs/jbd/transaction.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/fs/jbd/transaction.c 2003-08-25 23:37:33.000000000 +0200 >@@ -56,7 +56,11 @@ > transaction->t_journal = journal; > transaction->t_state = T_RUNNING; > transaction->t_tid = journal->j_transaction_sequence++; >- transaction->t_expires = jiffies + journal->j_commit_interval; >+ /* >+ * have to do it here, otherwise changed age_buffers since boot >+ * wont have any effect >+ */ >+ transaction->t_expires = jiffies + get_buffer_flushtime(); > INIT_LIST_HEAD(&transaction->t_jcb); > > /* Set up the commit timer for the new transaction. */ >diff -Naur linux-2.4.22-ppc-dev.orig/fs/namespace.c linux-2.4.22-ppc-dev/fs/namespace.c >--- linux-2.4.22-ppc-dev.orig/fs/namespace.c 2003-06-13 16:51:37.000000000 +0200 >+++ linux-2.4.22-ppc-dev/fs/namespace.c 2003-08-25 23:37:52.000000000 +0200 >@@ -763,7 +763,7 @@ > return -EPERM; > } > >- new_ns = kmalloc(sizeof(struct namespace *), GFP_KERNEL); >+ new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); > if (!new_ns) > goto out; > >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/elf.h linux-2.4.22-ppc-dev/include/asm-ppc/elf.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/elf.h 2003-06-13 16:51:38.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/elf.h 2003-08-25 23:37:49.000000000 +0200 >@@ -10,7 +10,7 @@ > > #define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ > #define ELF_NFPREG 33 /* includes fpscr */ >-#define ELF_NVRREG 33 /* includes vscr */ >+#define ELF_NVRREG 33 /* includes vscr & vrsave */ > > /* > * These are used to set parameters in the core dumps. >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/hardirq.h linux-2.4.22-ppc-dev/include/asm-ppc/hardirq.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/hardirq.h 2003-08-27 15:18:12.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/hardirq.h 2003-08-25 23:37:43.000000000 +0200 >@@ -54,12 +54,24 @@ > extern unsigned volatile long global_irq_lock; > extern atomic_t global_irq_count; > >+#ifdef CONFIG_DEBUG_SPINLOCK >+extern int debug_long_irqlock; >+extern void print_backtrace(unsigned long *sp); >+#endif /* CONFIG_DEBUG_SPINLOCK */ >+ > static inline void release_irqlock(int cpu) > { > /* if we didn't own the irq lock, just ignore.. */ > if (global_irq_holder == (unsigned char) cpu) { > global_irq_holder = NO_PROC_ID; > clear_bit(0,&global_irq_lock); >+#ifdef CONFIG_DEBUG_SPINLOCK >+ if (debug_long_irqlock) { >+ debug_long_irqlock = 0; >+ printk("Release long irq lock\n"); >+ print_backtrace(NULL); >+ } >+#endif /* CONFIG_DEBUG_SPINLOCK */ > } > } > >@@ -79,6 +91,9 @@ > } > if (loops-- == 0) { > printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); >+#ifdef CONFIG_DEBUG_SPINLOCK >+ debug_long_irqlock = 1; >+#endif > #ifdef CONFIG_XMON > xmon(0); > #endif >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/highmem.h linux-2.4.22-ppc-dev/include/asm-ppc/highmem.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/highmem.h 2003-08-27 15:18:12.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/highmem.h 2003-08-25 23:37:46.000000000 +0200 >@@ -28,7 +28,7 @@ > #include <asm/pgtable.h> > > /* undef for production */ >-#define HIGHMEM_DEBUG 1 >+#define HIGHMEM_DEBUG 0 > > extern pte_t *kmap_pte; > extern pgprot_t kmap_prot; >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/ide.h linux-2.4.22-ppc-dev/include/asm-ppc/ide.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/ide.h 2003-06-13 16:51:38.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/ide.h 2003-08-25 23:37:54.000000000 +0200 >@@ -34,6 +34,7 @@ > ide_ioreg_t data_port, > ide_ioreg_t ctrl_port, > int *irq); >+ int (*reserved_hwifs)(void); > }; > > extern struct ide_machdep_calls ppc_ide_md; >@@ -112,6 +113,17 @@ > #define IDE_ARCH_ACK_INTR 1 > #endif > >+/* >+ * How many IDE slots are "reserved" for bootable devices >+ */ >+#define IDE_ARCH_RESERVED_HWIFS 1 >+static inline int ide_reserved_hwifs(void) >+{ >+ if (ppc_ide_md.reserved_hwifs) >+ return ppc_ide_md.reserved_hwifs(); >+ return 2; >+} >+ > #endif /* __KERNEL__ */ > > #endif /* __ASMPPC_IDE_H */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/io.h linux-2.4.22-ppc-dev/include/asm-ppc/io.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/io.h 2003-08-27 15:18:12.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/io.h 2003-08-25 23:37:53.000000000 +0200 >@@ -287,9 +287,15 @@ > /* Enforce in-order execution of data I/O. > * No distinction between read/write on PPC; use eieio for all three. > */ >-#define iobarrier_rw() eieio() >-#define iobarrier_r() eieio() >-#define iobarrier_w() eieio() >+#if 0 >+#define iobarrier_rw() eieio() >+#define iobarrier_r() eieio() >+#define iobarrier_w() eieio() >+#endif >+extern inline void io_barrier(void) >+{ >+ __asm__ __volatile__ ("sync" : : : "memory"); >+} > > /* > * 8, 16 and 32 bit, big and little endian I/O operations, with barrier. >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/page.h linux-2.4.22-ppc-dev/include/asm-ppc/page.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/page.h 2003-08-27 15:18:12.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/page.h 2003-08-25 23:37:29.000000000 +0200 >@@ -17,7 +17,9 @@ > #include <asm/system.h> /* for xmon definition */ > > #ifdef CONFIG_XMON >+extern void xmon_printf(const char *fmt, ...); > #define BUG() do { \ >+ xmon_printf("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ > printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ > xmon(0); \ > } while (0) >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/pmac_feature.h linux-2.4.22-ppc-dev/include/asm-ppc/pmac_feature.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/pmac_feature.h 2003-08-27 15:18:12.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/pmac_feature.h 2003-08-25 23:37:31.000000000 +0200 >@@ -96,8 +96,8 @@ > #define PMAC_TYPE_UNKNOWN_CORE99 0x5f > > /* MacRisc2 with UniNorth 2.0 */ >-#define PMAC_TYPE_RACKMAC 0x80 /* XServe */ >-#define PMAC_TYPE_WINDTUNNEL 0x81 >+#define PMAC_TYPE_RACKMAC 0x80 /* XServes (all) */ >+#define PMAC_TYPE_WINDTUNNEL 0x81 /* Windtunnel */ > > /* MacRISC2 machines based on the Pangea chipset > */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/ppc4xx_serial.h linux-2.4.22-ppc-dev/include/asm-ppc/ppc4xx_serial.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/ppc4xx_serial.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/ppc4xx_serial.h 2003-08-25 23:37:41.000000000 +0200 >@@ -0,0 +1,101 @@ >+/* >+ * Copyright 2000 MontaVista Software Inc. >+ * PPC405GP modifications >+ * Author: MontaVista Software, Inc. >+ * frank_rowand@mvista.com or source@mvista.com >+ * debbie_chu@mvista.com >+ * >+ * Module name: ppc405_serial.h >+ * >+ * Description: >+ * Macros, definitions, and data structures specific to the IBM PowerPC >+ * 405 on-chip serial port devices. >+ */ >+ >+#ifdef __KERNEL__ >+#ifndef __ASMPPC_PPC4xx_SERIAL_H >+#define __ASMPPC_PPC4xx_SERIAL_H >+ >+#include <linux/config.h> >+ >+#ifdef CONFIG_SERIAL_MANY_PORTS >+#define RS_TABLE_SIZE 64 >+#else >+#define RS_TABLE_SIZE 4 >+#endif >+ >+#define PPC405GP_UART0_INT 0 >+#define PPC405GP_UART1_INT 1 >+ >+/* >+** 405GP UARTs are *not* PCI devices, so need to specify a non-pci memory >+** address and an io_type of SERIAL_IO_MEM. >+*/ >+ >+#define PPC405GP_UART0_IO_BASE (u8 *) 0xef600300 >+#define PPC405GP_UART1_IO_BASE (u8 *) 0xef600400 >+ >+/* >+** - there is no config option for this >+** - this name could be more informative >+** - also see arch/ppc/kernel/ppc405_serial.c >+** >+** #define CONFIG_PPC405GP_INTERNAL_CLOCK >+*/ >+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK >+#define BASE_BAUD 201600 >+#else >+#define BASE_BAUD 691200 >+#endif >+ >+ >+#ifdef CONFIG_SERIAL_DETECT_IRQ >+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) >+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) >+#else >+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) >+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) >+#endif >+ >+ >+#ifdef CONFIG_STB03XXX >+ >+#define UART0_IO_BASE 0x40040000 >+#define UART0_INT 20 >+ >+#define STD_SERIAL_PORT_DFNS \ >+ /* ttyS0 */ \ >+ { 0, BASE_BAUD, 0, UART0_INT, STD_COM_FLAGS, 0, 0, 0, 0, 0, 0, 0, \ >+ UART0_IO_BASE, 0, 0, 0, {}, {}, {}, SERIAL_IO_MEM, NULL }, >+ >+#elif defined(CONFIG_UART1_DFLT_CONSOLE) >+ >+#define STD_SERIAL_PORT_DFNS \ >+ /* ttyS1 */ \ >+ { 0, BASE_BAUD, 0, PPC405GP_UART1_INT, STD_COM_FLAGS, 0, 0, 0, 0, 0, 0, 0, \ >+ PPC405GP_UART1_IO_BASE, 0, 0, 0, {}, {}, {}, SERIAL_IO_MEM, NULL }, \ >+ /* ttyS0 */ \ >+ { 0, BASE_BAUD, 0, PPC405GP_UART0_INT, STD_COM_FLAGS, 0, 0, 0, 0, 0, 0, 0, \ >+ PPC405GP_UART0_IO_BASE, 0, 0, 0, {}, {}, {}, SERIAL_IO_MEM, NULL }, >+ >+#else >+ >+#define STD_SERIAL_PORT_DFNS \ >+ /* ttyS0 */ \ >+ { 0, BASE_BAUD, 0, PPC405GP_UART0_INT, STD_COM_FLAGS, 0, 0, 0, 0, 0, 0, 0, \ >+ PPC405GP_UART0_IO_BASE, 0, 0, 0, {}, {}, {}, SERIAL_IO_MEM, NULL }, \ >+ /* ttyS1 */ \ >+ { 0, BASE_BAUD, 0, PPC405GP_UART1_INT, STD_COM_FLAGS, 0, 0, 0, 0, 0, 0, 0, \ >+ PPC405GP_UART1_IO_BASE, 0, 0, 0, {}, {}, {}, SERIAL_IO_MEM, NULL }, >+ >+#endif >+ >+ >+#define SERIAL_PORT_DFNS \ >+ STD_SERIAL_PORT_DFNS \ >+ {} >+ >+ >+ >+#endif /* __ASMPPC_PPC4xx_SERIAL_H */ >+#endif /* __KERNEL__ */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/processor.h linux-2.4.22-ppc-dev/include/asm-ppc/processor.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/processor.h 2003-08-27 15:18:12.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/processor.h 2003-08-25 23:37:31.000000000 +0200 >@@ -716,6 +716,7 @@ > vector128 vr[32]; /* Complete AltiVec set */ > vector128 vscr; /* AltiVec status */ > unsigned long vrsave; >+ int used_vr; /* set if process has used altivec */ > #endif /* CONFIG_ALTIVEC */ > #if defined(CONFIG_4xx) > /* Saved 4xx debug registers */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/sigcontext.h linux-2.4.22-ppc-dev/include/asm-ppc/sigcontext.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/sigcontext.h 2003-06-13 16:51:38.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/sigcontext.h 2003-08-25 23:37:40.000000000 +0200 >@@ -3,8 +3,7 @@ > > #include <asm/ptrace.h> > >- >-struct sigcontext_struct { >+struct sigcontext { > unsigned long _unused[4]; > int signal; > unsigned long handler; >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/smp.h linux-2.4.22-ppc-dev/include/asm-ppc/smp.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/smp.h 2003-06-13 16:51:38.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/smp.h 2003-08-25 23:37:54.000000000 +0200 >@@ -17,6 +17,8 @@ > > #ifndef __ASSEMBLY__ > >+#define cpu_online(cpu) (cpu_online_map & (1<<(cpu))) >+ > struct cpuinfo_PPC { > unsigned long loops_per_jiffy; > unsigned long pvr; >@@ -69,6 +71,8 @@ > > #else /* !(CONFIG_SMP) */ > >+#define cpu_online(cpu) ((cpu) == 0) >+ > #endif /* !(CONFIG_SMP) */ > > #endif /* !(_PPC_SMP_H) */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-ppc/ucontext.h linux-2.4.22-ppc-dev/include/asm-ppc/ucontext.h >--- linux-2.4.22-ppc-dev.orig/include/asm-ppc/ucontext.h 2003-06-13 16:51:38.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/asm-ppc/ucontext.h 2003-08-25 23:37:46.000000000 +0200 >@@ -1,14 +1,28 @@ > #ifndef _ASMPPC_UCONTEXT_H > #define _ASMPPC_UCONTEXT_H > >-/* Copied from i386. */ >+#include <asm/elf.h> >+#include <asm/signal.h> >+ >+struct mcontext { >+ elf_gregset_t mc_gregs; >+ elf_fpregset_t mc_fregs; >+ unsigned long mc_pad[2]; >+ elf_vrregset_t mc_vregs __attribute__((__aligned__(16))); >+}; > > struct ucontext { >- unsigned long uc_flags; >- struct ucontext *uc_link; >- stack_t uc_stack; >- struct sigcontext_struct uc_mcontext; >- sigset_t uc_sigmask; /* mask last for extensibility */ >+ unsigned long uc_flags; >+ struct ucontext *uc_link; >+ stack_t uc_stack; >+ int uc_pad[7]; >+ struct mcontext *uc_regs; /* backward compat */ >+ sigset_t uc_oldsigmask; /* backward compat */ >+ int uc_pad2; >+ sigset_t uc_sigmask; >+ /* glibc has 1024-bit signal masks, ours are 64-bit */ >+ int uc_maskext[30]; >+ struct mcontext uc_mcontext; > }; > > #endif /* !_ASMPPC_UCONTEXT_H */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/asm-x86_64/asm-macros.i linux-2.4.22-ppc-dev/include/asm-x86_64/asm-macros.i >--- linux-2.4.22-ppc-dev.orig/include/asm-x86_64/asm-macros.i 2002-11-29 00:53:15.000000000 +0100 >+++ linux-2.4.22-ppc-dev/include/asm-x86_64/asm-macros.i 1970-01-01 01:00:00.000000000 +0100 >@@ -1,12 +0,0 @@ >- >- .macro SAVE_CALLEE_CLOBBERED >- cld >- pushq %rdi >- pushq %rsi >- pushq %rdx >- pushq %rcx >- pushq %rbx >- pushq %rax >- pushq %r8 >- pushq %r9" >- .endm >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/agp_backend.h linux-2.4.22-ppc-dev/include/linux/agp_backend.h >--- linux-2.4.22-ppc-dev.orig/include/linux/agp_backend.h 2003-08-27 15:18:13.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/agp_backend.h 2003-08-25 23:37:27.000000000 +0200 >@@ -90,6 +90,7 @@ > NVIDIA_NFORCE2, > NVIDIA_GENERIC, > HP_ZX1, >+ APPLE_UNINORTH > }; > > typedef struct _agp_version { >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/blkdev.h linux-2.4.22-ppc-dev/include/linux/blkdev.h >--- linux-2.4.22-ppc-dev.orig/include/linux/blkdev.h 2003-08-27 15:18:13.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/blkdev.h 2003-08-25 23:37:27.000000000 +0200 >@@ -63,6 +63,8 @@ > typedef int (make_request_fn) (request_queue_t *q, int rw, struct buffer_head *bh); > typedef void (plug_device_fn) (request_queue_t *q, kdev_t device); > typedef void (unplug_device_fn) (void *q); >+typedef void (activity_fn) (void *data, int rw); >+ > > struct request_list { > unsigned int count; >@@ -114,12 +116,16 @@ > merge_requests_fn * merge_requests_fn; > make_request_fn * make_request_fn; > plug_device_fn * plug_device_fn; >+ activity_fn * activity_fn; >+ > /* > * The queue owner gets to use this for whatever they like. > * ll_rw_blk doesn't touch it. > */ > void * queuedata; > >+ void * activity_data; >+ > /* > * This is used to remove the plug when tq_disk runs. > */ >@@ -246,6 +252,7 @@ > extern void blk_queue_throttle_sectors(request_queue_t *, int); > extern void blk_queue_make_request(request_queue_t *, make_request_fn *); > extern void generic_unplug_device(void *); >+extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); > extern inline int blk_seg_merge_ok(struct buffer_head *, struct buffer_head *); > > extern int * blk_size[MAX_BLKDEV]; >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/cpufreq.h linux-2.4.22-ppc-dev/include/linux/cpufreq.h >--- linux-2.4.22-ppc-dev.orig/include/linux/cpufreq.h 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/include/linux/cpufreq.h 2003-08-25 23:37:56.000000000 +0200 >@@ -0,0 +1,247 @@ >+/* >+ * linux/include/linux/cpufreq.h >+ * >+ * Copyright (C) 2001 Russell King >+ * (C) 2002 Dominik Brodowski <linux@brodo.de> >+ * >+ * >+ * $Id: cpufreq.h,v 1.29 2002/11/11 15:35:47 db Exp $ >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License version 2 as >+ * published by the Free Software Foundation. >+ */ >+#ifndef _LINUX_CPUFREQ_H >+#define _LINUX_CPUFREQ_H >+ >+#include <linux/config.h> >+#include <linux/notifier.h> >+#include <linux/threads.h> >+ >+ >+/********************************************************************* >+ * CPUFREQ NOTIFIER INTERFACE * >+ *********************************************************************/ >+ >+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); >+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); >+ >+#define CPUFREQ_TRANSITION_NOTIFIER (0) >+#define CPUFREQ_POLICY_NOTIFIER (1) >+ >+#define CPUFREQ_ALL_CPUS ((NR_CPUS)) >+ >+ >+/********************** cpufreq policy notifiers *********************/ >+ >+#define CPUFREQ_POLICY_POWERSAVE (1) >+#define CPUFREQ_POLICY_PERFORMANCE (2) >+ >+/* values here are CPU kHz so that hardware which doesn't run with some >+ * frequencies can complain without having to guess what per cent / per >+ * mille means. */ >+struct cpufreq_policy { >+ unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ >+ unsigned int min; /* in kHz */ >+ unsigned int max; /* in kHz */ >+ unsigned int policy; /* see above */ >+ unsigned int max_cpu_freq; /* for information */ >+}; >+ >+#define CPUFREQ_ADJUST (0) >+#define CPUFREQ_INCOMPATIBLE (1) >+#define CPUFREQ_NOTIFY (2) >+ >+ >+/******************** cpufreq transition notifiers *******************/ >+ >+#define CPUFREQ_PRECHANGE (0) >+#define CPUFREQ_POSTCHANGE (1) >+ >+struct cpufreq_freqs { >+ unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ >+ unsigned int old; >+ unsigned int new; >+}; >+ >+ >+/** >+ * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch safe) >+ * @old: old value >+ * @div: divisor >+ * @mult: multiplier >+ * >+ * Needed for loops_per_jiffy and similar calculations. We do it >+ * this way to avoid math overflow on 32-bit machines. This will >+ * become architecture dependent once high-resolution-timer is >+ * merged (or any other thing that introduces sc_math.h). >+ * >+ * new = old * mult / div >+ */ >+static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult) >+{ >+ unsigned long val, carry; >+ >+ mult /= 100; >+ div /= 100; >+ val = (old / div) * mult; >+ carry = old % div; >+ carry = carry * mult / div; >+ >+ return carry + val; >+}; >+ >+ >+/********************************************************************* >+ * DYNAMIC CPUFREQ INTERFACE * >+ *********************************************************************/ >+#ifdef CONFIG_CPU_FREQ_DYNAMIC >+/* TBD */ >+#endif /* CONFIG_CPU_FREQ_DYNAMIC */ >+ >+ >+/********************************************************************* >+ * CPUFREQ DRIVER INTERFACE * >+ *********************************************************************/ >+ >+typedef int (*cpufreq_policy_t) (struct cpufreq_policy *policy); >+ >+struct cpufreq_driver { >+ /* needed by all drivers */ >+ cpufreq_policy_t verify; >+ cpufreq_policy_t setpolicy; >+ struct cpufreq_policy *policy; >+#ifdef CONFIG_CPU_FREQ_DYNAMIC >+ /* TBD */ >+#endif >+ /* 2.4. compatible API */ >+#ifdef CONFIG_CPU_FREQ_24_API >+ unsigned int cpu_min_freq[NR_CPUS]; >+ unsigned int cpu_cur_freq[NR_CPUS]; >+#endif >+}; >+ >+int cpufreq_register(struct cpufreq_driver *driver_data); >+int cpufreq_unregister(void); >+ >+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state); >+ >+ >+static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) >+{ >+ if (policy->min < min) >+ policy->min = min; >+ if (policy->max < min) >+ policy->max = min; >+ if (policy->min > max) >+ policy->min = max; >+ if (policy->max > max) >+ policy->max = max; >+ if (policy->min > policy->max) >+ policy->min = policy->max; >+ return; >+} >+ >+/********************************************************************* >+ * CPUFREQ 2.6. INTERFACE * >+ *********************************************************************/ >+int cpufreq_set_policy(struct cpufreq_policy *policy); >+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); >+ >+#ifdef CONFIG_PM >+int cpufreq_restore(void); >+#endif >+ >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+/********************************************************************* >+ * CPUFREQ 2.4. INTERFACE * >+ *********************************************************************/ >+int cpufreq_setmax(unsigned int cpu); >+int cpufreq_set(unsigned int kHz, unsigned int cpu); >+unsigned int cpufreq_get(unsigned int cpu); >+ >+/* /proc/sys/cpu */ >+enum { >+ CPU_NR = 1, /* compatibilty reasons */ >+ CPU_NR_0 = 1, >+ CPU_NR_1 = 2, >+ CPU_NR_2 = 3, >+ CPU_NR_3 = 4, >+ CPU_NR_4 = 5, >+ CPU_NR_5 = 6, >+ CPU_NR_6 = 7, >+ CPU_NR_7 = 8, >+ CPU_NR_8 = 9, >+ CPU_NR_9 = 10, >+ CPU_NR_10 = 11, >+ CPU_NR_11 = 12, >+ CPU_NR_12 = 13, >+ CPU_NR_13 = 14, >+ CPU_NR_14 = 15, >+ CPU_NR_15 = 16, >+ CPU_NR_16 = 17, >+ CPU_NR_17 = 18, >+ CPU_NR_18 = 19, >+ CPU_NR_19 = 20, >+ CPU_NR_20 = 21, >+ CPU_NR_21 = 22, >+ CPU_NR_22 = 23, >+ CPU_NR_23 = 24, >+ CPU_NR_24 = 25, >+ CPU_NR_25 = 26, >+ CPU_NR_26 = 27, >+ CPU_NR_27 = 28, >+ CPU_NR_28 = 29, >+ CPU_NR_29 = 30, >+ CPU_NR_30 = 31, >+ CPU_NR_31 = 32, >+}; >+ >+/* /proc/sys/cpu/{0,1,...,(NR_CPUS-1)} */ >+enum { >+ CPU_NR_FREQ_MAX = 1, >+ CPU_NR_FREQ_MIN = 2, >+ CPU_NR_FREQ = 3, >+}; >+ >+#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \ >+ .ctl_name = CPU_NR_FREQ_MAX, \ >+ .data = &cpu_max_freq[cpunr], \ >+ .procname = "speed-max", \ >+ .maxlen = sizeof(cpu_max_freq[cpunr]),\ >+ .mode = 0444, \ >+ .proc_handler = proc_dointvec, } >+ >+#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \ >+ .ctl_name = CPU_NR_FREQ_MIN, \ >+ .data = &cpu_min_freq[cpunr], \ >+ .procname = "speed-min", \ >+ .maxlen = sizeof(cpu_min_freq[cpunr]),\ >+ .mode = 0444, \ >+ .proc_handler = proc_dointvec, } >+ >+#define CTL_CPU_VARS_SPEED(cpunr) { \ >+ .ctl_name = CPU_NR_FREQ, \ >+ .procname = "speed", \ >+ .mode = 0644, \ >+ .proc_handler = cpufreq_procctl, \ >+ .strategy = cpufreq_sysctl, \ >+ .extra1 = (void*) (cpunr), } >+ >+#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\ >+ CTL_CPU_VARS_SPEED_MAX(cpunr), \ >+ CTL_CPU_VARS_SPEED_MIN(cpunr), \ >+ CTL_CPU_VARS_SPEED(cpunr), \ >+ { .ctl_name = 0, }, } >+ >+/* the ctl_table entry for each CPU */ >+#define CPU_ENUM(s) { \ >+ .ctl_name = (CPU_NR + s), \ >+ .procname = #s, \ >+ .mode = 0555, \ >+ .child = ctl_cpu_vars_##s } >+ >+#endif /* CONFIG_CPU_FREQ_24_API */ >+ >+#endif /* _LINUX_CPUFREQ_H */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/fs.h linux-2.4.22-ppc-dev/include/linux/fs.h >--- linux-2.4.22-ppc-dev.orig/include/linux/fs.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/fs.h 2003-08-25 23:37:37.000000000 +0200 >@@ -1255,6 +1255,7 @@ > } > > extern void set_buffer_flushtime(struct buffer_head *); >+extern unsigned long get_buffer_flushtime(void); > extern void balance_dirty(void); > extern int check_disk_change(kdev_t); > extern int invalidate_inodes(struct super_block *); >@@ -1445,8 +1446,10 @@ > return get_hash_table(sb->s_dev, block, sb->s_blocksize); > } > extern void wakeup_bdflush(void); >+extern void wakeup_kupdate(void); > extern void put_unused_buffer_head(struct buffer_head * bh); > extern struct buffer_head * get_unused_buffer_head(int async); >+extern int block_dump; > > extern int brw_page(int, struct page *, kdev_t, int [], int); > >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/ide.h linux-2.4.22-ppc-dev/include/linux/ide.h >--- linux-2.4.22-ppc-dev.orig/include/linux/ide.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/ide.h 2003-08-25 23:37:46.000000000 +0200 >@@ -345,6 +345,13 @@ > # define ide_ack_intr(hwif) (1) > #endif > >+/* Do we have arch-specififed "reserved" IDE slots for bootable >+ * devices ? By default, we have 2 >+ */ >+#ifndef IDE_ARCH_RESERVED_HWIFS >+# define ide_reserved_hwifs() 2 >+#endif >+ > /* Currently only Atari needs it */ > #ifndef IDE_ARCH_LOCK > # define ide_release_lock() do {} while (0) >@@ -1005,6 +1012,8 @@ > unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */ > > void *hwif_data; /* extra hwif data */ >+ >+ void (*led_act)(void *data, int rw); > } ide_hwif_t; > > /* >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/mm.h linux-2.4.22-ppc-dev/include/linux/mm.h >--- linux-2.4.22-ppc-dev.orig/include/linux/mm.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/mm.h 2003-08-25 23:37:48.000000000 +0200 >@@ -634,12 +634,26 @@ > > return gfp_mask; > } >- >-/* vma is the first one with address < vma->vm_end, >- * and even address < vma->vm_start. Have to extend vma. */ >-static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) >+ >+extern int heap_stack_gap; >+ >+/* >+ * vma is the first one with address < vma->vm_end, >+ * and even address < vma->vm_start. Have to extend vma. >+ * >+ * Locking: vm_start can decrease under you if you only hold >+ * the read semaphore, you either need the write semaphore >+ * or both the read semaphore and the page_table_lock acquired >+ * if you want vm_start consistent. vm_end and the vma layout >+ * are just consistent with only the read semaphore acquired >+ * instead. >+ */ >+#define EXPAND_STACK_HAS_3_ARGS >+static inline int expand_stack(struct vm_area_struct * vma, unsigned long address, >+ struct vm_area_struct * prev_vma) > { > unsigned long grow; >+ int err = -ENOMEM; > > /* > * vma->vm_start/vm_end cannot change under us because the caller is required >@@ -647,20 +661,23 @@ > * before relocating the vma range ourself. > */ > address &= PAGE_MASK; >- spin_lock(&vma->vm_mm->page_table_lock); >+ if (prev_vma && prev_vma->vm_end + (heap_stack_gap << PAGE_SHIFT) > address) >+ goto out; >+ spin_lock(&vma->vm_mm->page_table_lock); > grow = (vma->vm_start - address) >> PAGE_SHIFT; > if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || >- ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { >- spin_unlock(&vma->vm_mm->page_table_lock); >- return -ENOMEM; >- } >+ ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) >+ goto out_unlock; > vma->vm_start = address; > vma->vm_pgoff -= grow; > vma->vm_mm->total_vm += grow; > if (vma->vm_flags & VM_LOCKED) > vma->vm_mm->locked_vm += grow; >+ err = 0; >+ out_unlock: > spin_unlock(&vma->vm_mm->page_table_lock); >- return 0; >+ out: >+ return err; > } > > /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/pci_ids.h linux-2.4.22-ppc-dev/include/linux/pci_ids.h >--- linux-2.4.22-ppc-dev.orig/include/linux/pci_ids.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/pci_ids.h 2003-08-25 23:38:01.000000000 +0200 >@@ -403,9 +403,10 @@ > #define PCI_DEVICE_ID_IBM_MPIC 0x0046 > #define PCI_DEVICE_ID_IBM_3780IDSP 0x007d > #define PCI_DEVICE_ID_IBM_CHUKAR 0x0096 >+#define PCI_DEVICE_ID_IBM_CPC700 0x00f9 > #define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc > #define PCI_DEVICE_ID_IBM_CPC710_PCI32 0x0105 >-#define PCI_DEVICE_ID_IBM_405GP 0x0156 >+#define PCI_DEVICE_ID_IBM_405GP 0x0156 > #define PCI_DEVICE_ID_IBM_SERVERAIDI960 0x01bd > #define PCI_DEVICE_ID_IBM_MPIC_2 0xffff > >@@ -654,6 +655,7 @@ > #define PCI_DEVICE_ID_TI_4410 0xac41 > #define PCI_DEVICE_ID_TI_4451 0xac42 > #define PCI_DEVICE_ID_TI_1420 0xac51 >+#define PCI_DEVICE_ID_TI_1510 0xac56 > > #define PCI_VENDOR_ID_SONY 0x104d > #define PCI_DEVICE_ID_SONY_CXD3222 0x8039 >@@ -747,6 +749,10 @@ > #define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 > #define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d > #define PCI_DEVICE_ID_APPLE_UNI_N_FW2 0x0030 >+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032 >+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034 >+#define PCI_DEVICE_ID_APPLE_KEYLARGO_I 0x003e >+#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 > > #define PCI_VENDOR_ID_YAMAHA 0x1073 > #define PCI_DEVICE_ID_YAMAHA_724 0x0004 >@@ -957,33 +963,46 @@ > #define PCI_DEVICE_ID_CERN_HIPPI_DST 0x0021 > #define PCI_DEVICE_ID_CERN_HIPPI_SRC 0x0022 > >-#define PCI_VENDOR_ID_NVIDIA 0x10de >-#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020 >-#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028 >-#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029 >-#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C >-#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D >-#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 >-#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 >-#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112 >-#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 >-#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 >-#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 >-#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 >-#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc >-#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 >-#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 >-#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 >+#define PCI_VENDOR_ID_NVIDIA 0x10de >+#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020 >+#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028 >+#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029 >+#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C >+#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D >+#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460 0x0170 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440 0x0171 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420 0x0172 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO 0x0174 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO 0x0175 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL 0x0178 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200 0x017A >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C >+#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600 0x0250 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400 0x0251 >+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200 0x0253 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 >+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B > > #define PCI_VENDOR_ID_IMS 0x10e0 > #define PCI_DEVICE_ID_IMS_8849 0x8849 >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/pmu.h linux-2.4.22-ppc-dev/include/linux/pmu.h >--- linux-2.4.22-ppc-dev.orig/include/linux/pmu.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/pmu.h 2003-08-25 23:37:35.000000000 +0200 >@@ -143,6 +143,8 @@ > void (*done)(struct adb_request *), int nbytes, ...); > > extern void pmu_poll(void); >+extern void pmu_poll_adb(void); /* For use by xmon */ >+extern void pmu_wait_complete(struct adb_request *req); > > /* For use before switching interrupts off for a long time; > * warning: not stackable >@@ -154,6 +156,7 @@ > > extern void pmu_restart(void); > extern void pmu_shutdown(void); >+extern void pmu_unlock(void); > > extern int pmu_present(void); > extern int pmu_get_model(void); >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/sysctl.h linux-2.4.22-ppc-dev/include/linux/sysctl.h >--- linux-2.4.22-ppc-dev.orig/include/linux/sysctl.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/sysctl.h 2003-08-25 23:37:30.000000000 +0200 >@@ -146,6 +146,9 @@ > VM_MAX_MAP_COUNT=11, /* int: Maximum number of active map areas */ > VM_MIN_READAHEAD=12, /* Min file readahead */ > VM_MAX_READAHEAD=13, /* Max file readahead */ >+ VM_HEAP_STACK_GAP=14, /* int: page gap between heap and stack */ >+ VM_LAPTOP_MODE=15, >+ VM_BLOCK_DUMP=16, > }; > > >diff -Naur linux-2.4.22-ppc-dev.orig/include/linux/wait.h linux-2.4.22-ppc-dev/include/linux/wait.h >--- linux-2.4.22-ppc-dev.orig/include/linux/wait.h 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/include/linux/wait.h 2003-08-25 23:37:28.000000000 +0200 >@@ -90,11 +90,17 @@ > * spurious .aligns. > */ > #if WAITQUEUE_DEBUG >+#ifdef CONFIG_XMON >+extern void xmon_printf(const char* fmt, ...); >+#define wqbug_printf xmon_printf >+#else >+#define wqbug_printf printk >+#endif > #define WQ_BUG() BUG() > #define CHECK_MAGIC(x) \ > do { \ > if ((x) != (long)&(x)) { \ >- printk("bad magic %lx (should be %lx), ", \ >+ wqbug_printf("bad magic %lx (should be %lx), ", \ > (long)x, (long)&(x)); \ > WQ_BUG(); \ > } \ >@@ -102,7 +108,7 @@ > #define CHECK_MAGIC_WQHEAD(x) \ > do { \ > if ((x)->__magic != (long)&((x)->__magic)) { \ >- printk("bad magic %lx (should be %lx, creator %lx), ", \ >+ wqbug_printf("bad magic %lx (should be %lx, creator %lx), ", \ > (x)->__magic, (long)&((x)->__magic), (x)->__creator); \ > WQ_BUG(); \ > } \ >diff -Naur linux-2.4.22-ppc-dev.orig/init/main.c linux-2.4.22-ppc-dev/init/main.c >--- linux-2.4.22-ppc-dev.orig/init/main.c 2003-08-27 15:18:14.000000000 +0200 >+++ linux-2.4.22-ppc-dev/init/main.c 2003-08-25 23:37:53.000000000 +0200 >@@ -161,7 +161,7 @@ > better than 1% */ > #define LPS_PREC 8 > >-void __init calibrate_delay(void) >+void /*__init*/ calibrate_delay(void) > { > unsigned long ticks, loopbit; > int lps_precision = LPS_PREC; >diff -Naur linux-2.4.22-ppc-dev.orig/kernel/Makefile linux-2.4.22-ppc-dev/kernel/Makefile >--- linux-2.4.22-ppc-dev.orig/kernel/Makefile 2001-09-17 06:22:40.000000000 +0200 >+++ linux-2.4.22-ppc-dev/kernel/Makefile 2003-08-25 23:37:50.000000000 +0200 >@@ -9,7 +9,7 @@ > > O_TARGET := kernel.o > >-export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o >+export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o cpufreq.o > > obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ > module.o exit.o itimer.o info.o time.o softirq.o resource.o \ >@@ -19,6 +19,7 @@ > obj-$(CONFIG_UID16) += uid16.o > obj-$(CONFIG_MODULES) += ksyms.o > obj-$(CONFIG_PM) += pm.o >+obj-$(CONFIG_CPU_FREQ) += cpufreq.o > > ifneq ($(CONFIG_IA64),y) > # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is >diff -Naur linux-2.4.22-ppc-dev.orig/kernel/cpufreq.c linux-2.4.22-ppc-dev/kernel/cpufreq.c >--- linux-2.4.22-ppc-dev.orig/kernel/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 >+++ linux-2.4.22-ppc-dev/kernel/cpufreq.c 2003-08-25 23:37:32.000000000 +0200 >@@ -0,0 +1,1130 @@ >+/* >+ * linux/kernel/cpufreq.c >+ * >+ * Copyright (C) 2001 Russell King >+ * (C) 2002 Dominik Brodowski <linux@brodo.de> >+ * >+ * $Id: cpufreq.c,v 1.50 2002/11/11 15:35:48 db Exp $ >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License version 2 as >+ * published by the Free Software Foundation. >+ * >+ */ >+ >+#include <linux/kernel.h> >+#include <linux/module.h> >+#include <linux/init.h> >+#include <linux/notifier.h> >+#include <linux/cpufreq.h> >+#include <linux/delay.h> >+#include <asm/system.h> >+#include <linux/interrupt.h> >+#include <linux/spinlock.h> >+#include <linux/ctype.h> >+#include <linux/proc_fs.h> >+ >+#include <asm/uaccess.h> >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+#include <linux/sysctl.h> >+#endif >+ >+ >+/** >+ * The "cpufreq driver" - the arch- or hardware-dependend low >+ * level driver of CPUFreq support, and its locking mutex. >+ * cpu_max_freq is in kHz. >+ */ >+static struct cpufreq_driver *cpufreq_driver; >+static DECLARE_MUTEX (cpufreq_driver_sem); >+ >+ >+/** >+ * Two notifier lists: the "policy" list is involved in the >+ * validation process for a new CPU frequency policy; the >+ * "transition" list for kernel code that needs to handle >+ * changes to devices when the CPU clock speed changes. >+ * The mutex locks both lists. If both cpufreq_driver_sem >+ * and cpufreq_notifier_sem need to be hold, get cpufreq_driver_sem >+ * first. >+ */ >+static struct notifier_block *cpufreq_policy_notifier_list; >+static struct notifier_block *cpufreq_transition_notifier_list; >+static DECLARE_MUTEX (cpufreq_notifier_sem); >+ >+ >+/** >+ * The cpufreq default policy. Can be set by a "cpufreq=..." command >+ * line option. >+ */ >+static struct cpufreq_policy default_policy = { >+ .cpu = CPUFREQ_ALL_CPUS, >+ .min = 0, >+ .max = 0, >+ .policy = 0, >+}; >+ >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+/** >+ * A few values needed by the 2.4.-compatible API >+ */ >+static unsigned int cpu_max_freq[NR_CPUS]; >+static unsigned int cpu_min_freq[NR_CPUS]; >+static unsigned int cpu_cur_freq[NR_CPUS]; >+#endif >+ >+ >+ >+/********************************************************************* >+ * 2.6. API * >+ *********************************************************************/ >+ >+/** >+ * cpufreq_parse_policy - parse a policy string >+ * @input_string: the string to parse. >+ * @policy: the policy written inside input_string >+ * >+ * This function parses a "policy string" - something the user echo'es into >+ * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy. >+ * If there are invalid/missing entries, they are replaced with current >+ * cpufreq policy. >+ */ >+static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy) >+{ >+ unsigned int min = 0; >+ unsigned int max = 0; >+ unsigned int cpu = 0; >+ char policy_string[42] = {'\0'}; >+ struct cpufreq_policy current_policy; >+ unsigned int result = -EFAULT; >+ unsigned int i = 0; >+ >+ if (!policy) >+ return -EINVAL; >+ >+ policy->min = 0; >+ policy->max = 0; >+ policy->policy = 0; >+ policy->cpu = CPUFREQ_ALL_CPUS; >+ >+ if (sscanf(input_string, "%d:%d:%d:%s", &cpu, &min, &max, policy_string) == 4) >+ { >+ policy->min = min; >+ policy->max = max; >+ policy->cpu = cpu; >+ result = 0; >+ goto scan_policy; >+ } >+ if (sscanf(input_string, "%d%%%d%%%d%%%s", &cpu, &min, &max, policy_string) == 4) >+ { >+ if (!cpufreq_get_policy(¤t_policy, cpu)) { >+ policy->min = (min * current_policy.max_cpu_freq) / 100; >+ policy->max = (max * current_policy.max_cpu_freq) / 100; >+ policy->cpu = cpu; >+ result = 0; >+ goto scan_policy; >+ } >+ } >+ >+ if (sscanf(input_string, "%d:%d:%s", &min, &max, policy_string) == 3) >+ { >+ policy->min = min; >+ policy->max = max; >+ result = 0; >+ goto scan_policy; >+ } >+ >+ if (sscanf(input_string, "%d%%%d%%%s", &min, &max, policy_string) == 3) >+ { >+ if (!cpufreq_get_policy(¤t_policy, cpu)) { >+ policy->min = (min * current_policy.max_cpu_freq) / 100; >+ policy->max = (max * current_policy.max_cpu_freq) / 100; >+ result = 0; >+ goto scan_policy; >+ } >+ } >+ >+ return -EINVAL; >+ >+scan_policy: >+ >+ for (i=0;i<sizeof(policy_string);i++){ >+ if (policy_string[i]=='\0') >+ break; >+ policy_string[i] = tolower(policy_string[i]); >+ } >+ >+ if (!strncmp(policy_string, "powersave", 6) || >+ !strncmp(policy_string, "eco", 3) || >+ !strncmp(policy_string, "batter", 6) || >+ !strncmp(policy_string, "low", 3)) >+ { >+ result = 0; >+ policy->policy = CPUFREQ_POLICY_POWERSAVE; >+ } >+ else if (!strncmp(policy_string, "performance",6) || >+ !strncmp(policy_string, "high",4) || >+ !strncmp(policy_string, "full",4)) >+ { >+ result = 0; >+ policy->policy = CPUFREQ_POLICY_PERFORMANCE; >+ } >+ else if (!cpufreq_get_policy(¤t_policy, policy->cpu)) >+ { >+ policy->policy = current_policy.policy; >+ } >+ else >+ { >+ policy->policy = 0; >+ } >+ >+ return result; >+} >+ >+ >+/* >+ * cpufreq command line parameter. Must be hard values (kHz) >+ * cpufreq=1000000:2000000:PERFORMANCE >+ * to set the default CPUFreq policy. >+ */ >+static int __init cpufreq_setup(char *str) >+{ >+ cpufreq_parse_policy(str, &default_policy); >+ default_policy.cpu = CPUFREQ_ALL_CPUS; >+ return 1; >+} >+__setup("cpufreq=", cpufreq_setup); >+ >+ >+#ifdef CONFIG_PROC_FS >+ >+/** >+ * cpufreq_proc_read - read /proc/cpufreq >+ * >+ * This function prints out the current cpufreq policy. >+ */ >+static int cpufreq_proc_read ( >+ char *page, >+ char **start, >+ off_t off, >+ int count, >+ int *eof, >+ void *data) >+{ >+ char *p = page; >+ int len = 0; >+ struct cpufreq_policy policy; >+ unsigned int min_pctg = 0; >+ unsigned int max_pctg = 0; >+ unsigned int i = 0; >+ >+ if (off != 0) >+ goto end; >+ >+ p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n"); >+ for (i=0;i<NR_CPUS;i++) { >+ if (!cpu_online(i)) >+ continue; >+ >+ cpufreq_get_policy(&policy, i); >+ >+ if (!policy.max_cpu_freq) >+ continue; >+ >+ min_pctg = (policy.min * 100) / policy.max_cpu_freq; >+ max_pctg = (policy.max * 100) / policy.max_cpu_freq; >+ >+ p += sprintf(p, "CPU%3d %9d kHz (%3d %%) - %9d kHz (%3d %%) - ", >+ i , policy.min, min_pctg, policy.max, max_pctg); >+ switch (policy.policy) { >+ case CPUFREQ_POLICY_POWERSAVE: >+ p += sprintf(p, "powersave\n"); >+ break; >+ case CPUFREQ_POLICY_PERFORMANCE: >+ p += sprintf(p, "performance\n"); >+ break; >+ default: >+ p += sprintf(p, "INVALID\n"); >+ break; >+ } >+ } >+end: >+ len = (p - page); >+ if (len <= off+count) >+ *eof = 1; >+ *start = page + off; >+ len -= off; >+ if (len>count) >+ len = count; >+ if (len<0) >+ len = 0; >+ >+ return len; >+} >+ >+ >+/** >+ * cpufreq_proc_write - handles writing into /proc/cpufreq >+ * >+ * This function calls the parsing script and then sets the policy >+ * accordingly. >+ */ >+static int cpufreq_proc_write ( >+ struct file *file, >+ const char *buffer, >+ unsigned long count, >+ void *data) >+{ >+ int result = 0; >+ char proc_string[42] = {'\0'}; >+ struct cpufreq_policy policy; >+ >+ >+ if ((count > sizeof(proc_string) - 1)) >+ return -EINVAL; >+ >+ if (copy_from_user(proc_string, buffer, count)) >+ return -EFAULT; >+ >+ proc_string[count] = '\0'; >+ >+ result = cpufreq_parse_policy(proc_string, &policy); >+ if (result) >+ return -EFAULT; >+ >+ cpufreq_set_policy(&policy); >+ >+ return count; >+} >+ >+ >+/** >+ * cpufreq_proc_init - add "cpufreq" to the /proc root directory >+ * >+ * This function adds "cpufreq" to the /proc root directory. >+ */ >+static unsigned int cpufreq_proc_init (void) >+{ >+ struct proc_dir_entry *entry = NULL; >+ >+ /* are these acceptable values? */ >+ entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, >+ &proc_root); >+ >+ if (!entry) { >+ printk(KERN_ERR "unable to create /proc/cpufreq entry\n"); >+ return -EIO; >+ } else { >+ entry->read_proc = cpufreq_proc_read; >+ entry->write_proc = cpufreq_proc_write; >+ } >+ >+ return 0; >+} >+ >+ >+/** >+ * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory. >+ * >+ * This function removes "cpufreq" from the /proc root directory. >+ */ >+static void cpufreq_proc_exit (void) >+{ >+ remove_proc_entry("cpufreq", &proc_root); >+ return; >+} >+#endif /* CONFIG_PROC_FS */ >+ >+ >+ >+/********************************************************************* >+ * 2.4. COMPATIBLE API * >+ *********************************************************************/ >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+/** >+ * cpufreq_set - set the CPU frequency >+ * @freq: target frequency in kHz >+ * @cpu: CPU for which the frequency is to be set >+ * >+ * Sets the CPU frequency to freq. >+ */ >+int cpufreq_set(unsigned int freq, unsigned int cpu) >+{ >+ struct cpufreq_policy policy; >+ down(&cpufreq_driver_sem); >+ if (!cpufreq_driver || !cpu_max_freq) { >+ up(&cpufreq_driver_sem); >+ return -EINVAL; >+ } >+ >+ policy.min = freq; >+ policy.max = freq; >+ policy.policy = CPUFREQ_POLICY_POWERSAVE; >+ policy.cpu = cpu; >+ >+ up(&cpufreq_driver_sem); >+ >+ return cpufreq_set_policy(&policy); >+} >+EXPORT_SYMBOL_GPL(cpufreq_set); >+ >+ >+/** >+ * cpufreq_setmax - set the CPU to the maximum frequency >+ * @cpu - affected cpu; >+ * >+ * Sets the CPU frequency to the maximum frequency supported by >+ * this CPU. >+ */ >+int cpufreq_setmax(unsigned int cpu) >+{ >+ if (!cpu_online(cpu) && (cpu != CPUFREQ_ALL_CPUS)) >+ return -EINVAL; >+ return cpufreq_set(cpu_max_freq[cpu], cpu); >+} >+EXPORT_SYMBOL_GPL(cpufreq_setmax); >+ >+ >+/** >+ * cpufreq_get - get the current CPU frequency (in kHz) >+ * @cpu: CPU number - currently without effect. >+ * >+ * Get the CPU current (static) CPU frequency >+ */ >+unsigned int cpufreq_get(unsigned int cpu) >+{ >+ if (!cpu_online(cpu)) >+ return -EINVAL; >+ return cpu_cur_freq[cpu]; >+} >+EXPORT_SYMBOL(cpufreq_get); >+ >+ >+#ifdef CONFIG_SYSCTL >+ >+ >+/*********************** cpufreq_sysctl interface ********************/ >+static int >+cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, >+ void *buffer, size_t *lenp) >+{ >+ char buf[16], *p; >+ int cpu = (int) ctl->extra1; >+ int len, left = *lenp; >+ >+ if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) { >+ *lenp = 0; >+ return 0; >+ } >+ >+ if (write) { >+ unsigned int freq; >+ >+ len = left; >+ if (left > sizeof(buf)) >+ left = sizeof(buf); >+ if (copy_from_user(buf, buffer, left)) >+ return -EFAULT; >+ buf[sizeof(buf) - 1] = '\0'; >+ >+ freq = simple_strtoul(buf, &p, 0); >+ cpufreq_set(freq, cpu); >+ } else { >+ len = sprintf(buf, "%d\n", cpufreq_get(cpu)); >+ if (len > left) >+ len = left; >+ if (copy_to_user(buffer, buf, len)) >+ return -EFAULT; >+ } >+ >+ *lenp = len; >+ filp->f_pos += len; >+ return 0; >+} >+ >+static int >+cpufreq_sysctl(ctl_table *table, int *name, int nlen, >+ void *oldval, size_t *oldlenp, >+ void *newval, size_t newlen, void **context) >+{ >+ int cpu = (int) table->extra1; >+ >+ if (!cpu_online(cpu)) >+ return -EINVAL; >+ >+ if (oldval && oldlenp) { >+ size_t oldlen; >+ >+ if (get_user(oldlen, oldlenp)) >+ return -EFAULT; >+ >+ if (oldlen != sizeof(unsigned int)) >+ return -EINVAL; >+ >+ if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) || >+ put_user(sizeof(unsigned int), oldlenp)) >+ return -EFAULT; >+ } >+ if (newval && newlen) { >+ unsigned int freq; >+ >+ if (newlen != sizeof(unsigned int)) >+ return -EINVAL; >+ >+ if (get_user(freq, (unsigned int *)newval)) >+ return -EFAULT; >+ >+ cpufreq_set(freq, cpu); >+ } >+ return 1; >+} >+ >+/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */ >+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ >+ CTL_TABLE_CPU_VARS(0); >+#if NR_CPUS > 1 >+ CTL_TABLE_CPU_VARS(1); >+#endif >+#if NR_CPUS > 2 >+ CTL_TABLE_CPU_VARS(2); >+#endif >+#if NR_CPUS > 3 >+ CTL_TABLE_CPU_VARS(3); >+#endif >+#if NR_CPUS > 4 >+ CTL_TABLE_CPU_VARS(4); >+#endif >+#if NR_CPUS > 5 >+ CTL_TABLE_CPU_VARS(5); >+#endif >+#if NR_CPUS > 6 >+ CTL_TABLE_CPU_VARS(6); >+#endif >+#if NR_CPUS > 7 >+ CTL_TABLE_CPU_VARS(7); >+#endif >+#if NR_CPUS > 8 >+ CTL_TABLE_CPU_VARS(8); >+#endif >+#if NR_CPUS > 9 >+ CTL_TABLE_CPU_VARS(9); >+#endif >+#if NR_CPUS > 10 >+ CTL_TABLE_CPU_VARS(10); >+#endif >+#if NR_CPUS > 11 >+ CTL_TABLE_CPU_VARS(11); >+#endif >+#if NR_CPUS > 12 >+ CTL_TABLE_CPU_VARS(12); >+#endif >+#if NR_CPUS > 13 >+ CTL_TABLE_CPU_VARS(13); >+#endif >+#if NR_CPUS > 14 >+ CTL_TABLE_CPU_VARS(14); >+#endif >+#if NR_CPUS > 15 >+ CTL_TABLE_CPU_VARS(15); >+#endif >+#if NR_CPUS > 16 >+ CTL_TABLE_CPU_VARS(16); >+#endif >+#if NR_CPUS > 17 >+ CTL_TABLE_CPU_VARS(17); >+#endif >+#if NR_CPUS > 18 >+ CTL_TABLE_CPU_VARS(18); >+#endif >+#if NR_CPUS > 19 >+ CTL_TABLE_CPU_VARS(19); >+#endif >+#if NR_CPUS > 20 >+ CTL_TABLE_CPU_VARS(20); >+#endif >+#if NR_CPUS > 21 >+ CTL_TABLE_CPU_VARS(21); >+#endif >+#if NR_CPUS > 22 >+ CTL_TABLE_CPU_VARS(22); >+#endif >+#if NR_CPUS > 23 >+ CTL_TABLE_CPU_VARS(23); >+#endif >+#if NR_CPUS > 24 >+ CTL_TABLE_CPU_VARS(24); >+#endif >+#if NR_CPUS > 25 >+ CTL_TABLE_CPU_VARS(25); >+#endif >+#if NR_CPUS > 26 >+ CTL_TABLE_CPU_VARS(26); >+#endif >+#if NR_CPUS > 27 >+ CTL_TABLE_CPU_VARS(27); >+#endif >+#if NR_CPUS > 28 >+ CTL_TABLE_CPU_VARS(28); >+#endif >+#if NR_CPUS > 29 >+ CTL_TABLE_CPU_VARS(29); >+#endif >+#if NR_CPUS > 30 >+ CTL_TABLE_CPU_VARS(30); >+#endif >+#if NR_CPUS > 31 >+ CTL_TABLE_CPU_VARS(31); >+#endif >+#if NR_CPUS > 32 >+#error please extend CPU enumeration >+#endif >+ >+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ >+static ctl_table ctl_cpu_table[NR_CPUS + 1] = { >+ CPU_ENUM(0), >+#if NR_CPUS > 1 >+ CPU_ENUM(1), >+#endif >+#if NR_CPUS > 2 >+ CPU_ENUM(2), >+#endif >+#if NR_CPUS > 3 >+ CPU_ENUM(3), >+#endif >+#if NR_CPUS > 4 >+ CPU_ENUM(4), >+#endif >+#if NR_CPUS > 5 >+ CPU_ENUM(5), >+#endif >+#if NR_CPUS > 6 >+ CPU_ENUM(6), >+#endif >+#if NR_CPUS > 7 >+ CPU_ENUM(7), >+#endif >+#if NR_CPUS > 8 >+ CPU_ENUM(8), >+#endif >+#if NR_CPUS > 9 >+ CPU_ENUM(9), >+#endif >+#if NR_CPUS > 10 >+ CPU_ENUM(10), >+#endif >+#if NR_CPUS > 11 >+ CPU_ENUM(11), >+#endif >+#if NR_CPUS > 12 >+ CPU_ENUM(12), >+#endif >+#if NR_CPUS > 13 >+ CPU_ENUM(13), >+#endif >+#if NR_CPUS > 14 >+ CPU_ENUM(14), >+#endif >+#if NR_CPUS > 15 >+ CPU_ENUM(15), >+#endif >+#if NR_CPUS > 16 >+ CPU_ENUM(16), >+#endif >+#if NR_CPUS > 17 >+ CPU_ENUM(17), >+#endif >+#if NR_CPUS > 18 >+ CPU_ENUM(18), >+#endif >+#if NR_CPUS > 19 >+ CPU_ENUM(19), >+#endif >+#if NR_CPUS > 20 >+ CPU_ENUM(20), >+#endif >+#if NR_CPUS > 21 >+ CPU_ENUM(21), >+#endif >+#if NR_CPUS > 22 >+ CPU_ENUM(22), >+#endif >+#if NR_CPUS > 23 >+ CPU_ENUM(23), >+#endif >+#if NR_CPUS > 24 >+ CPU_ENUM(24), >+#endif >+#if NR_CPUS > 25 >+ CPU_ENUM(25), >+#endif >+#if NR_CPUS > 26 >+ CPU_ENUM(26), >+#endif >+#if NR_CPUS > 27 >+ CPU_ENUM(27), >+#endif >+#if NR_CPUS > 28 >+ CPU_ENUM(28), >+#endif >+#if NR_CPUS > 29 >+ CPU_ENUM(29), >+#endif >+#if NR_CPUS > 30 >+ CPU_ENUM(30), >+#endif >+#if NR_CPUS > 31 >+ CPU_ENUM(31), >+#endif >+#if NR_CPUS > 32 >+#error please extend CPU enumeration >+#endif >+ { >+ .ctl_name = 0, >+ } >+}; >+ >+static ctl_table ctl_cpu[2] = { >+ { >+ .ctl_name = CTL_CPU, >+ .procname = "cpu", >+ .mode = 0555, >+ .child = ctl_cpu_table, >+ }, >+ { >+ .ctl_name = 0, >+ } >+}; >+ >+struct ctl_table_header *cpufreq_sysctl_table; >+ >+static inline void cpufreq_sysctl_init(void) >+{ >+ cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0); >+} >+ >+static inline void cpufreq_sysctl_exit(void) >+{ >+ unregister_sysctl_table(cpufreq_sysctl_table); >+} >+ >+#else >+#define cpufreq_sysctl_init() >+#define cpufreq_sysctl_exit() >+#endif /* CONFIG_SYSCTL */ >+#endif /* CONFIG_CPU_FREQ_24_API */ >+ >+ >+ >+/********************************************************************* >+ * NOTIFIER LISTS INTERFACE * >+ *********************************************************************/ >+ >+/** >+ * cpufreq_register_notifier - register a driver with cpufreq >+ * @nb: notifier function to register >+ * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER >+ * >+ * Add a driver to one of two lists: either a list of drivers that >+ * are notified about clock rate changes (once before and once after >+ * the transition), or a list of drivers that are notified about >+ * changes in cpufreq policy. >+ * >+ * This function may sleep, and has the same return conditions as >+ * notifier_chain_register. >+ */ >+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) >+{ >+ int ret; >+ >+ down(&cpufreq_notifier_sem); >+ switch (list) { >+ case CPUFREQ_TRANSITION_NOTIFIER: >+ ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb); >+ break; >+ case CPUFREQ_POLICY_NOTIFIER: >+ ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb); >+ break; >+ default: >+ ret = -EINVAL; >+ } >+ up(&cpufreq_notifier_sem); >+ >+ return ret; >+} >+EXPORT_SYMBOL(cpufreq_register_notifier); >+ >+ >+/** >+ * cpufreq_unregister_notifier - unregister a driver with cpufreq >+ * @nb: notifier block to be unregistered >+ * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER >+ * >+ * Remove a driver from the CPU frequency notifier list. >+ * >+ * This function may sleep, and has the same return conditions as >+ * notifier_chain_unregister. >+ */ >+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) >+{ >+ int ret; >+ >+ down(&cpufreq_notifier_sem); >+ switch (list) { >+ case CPUFREQ_TRANSITION_NOTIFIER: >+ ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb); >+ break; >+ case CPUFREQ_POLICY_NOTIFIER: >+ ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb); >+ break; >+ default: >+ ret = -EINVAL; >+ } >+ up(&cpufreq_notifier_sem); >+ >+ return ret; >+} >+EXPORT_SYMBOL(cpufreq_unregister_notifier); >+ >+ >+ >+/********************************************************************* >+ * POLICY INTERFACE * >+ *********************************************************************/ >+ >+/** >+ * cpufreq_get_policy - get the current cpufreq_policy >+ * @policy: struct cpufreq_policy into which the current cpufreq_policy is written >+ * >+ * Reads the current cpufreq policy. >+ */ >+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) >+{ >+ down(&cpufreq_driver_sem); >+ if (!cpufreq_driver || !policy || >+ (cpu >= NR_CPUS) || (!cpu_online(cpu))) { >+ up(&cpufreq_driver_sem); >+ return -EINVAL; >+ } >+ >+ policy->min = cpufreq_driver->policy[cpu].min; >+ policy->max = cpufreq_driver->policy[cpu].max; >+ policy->policy = cpufreq_driver->policy[cpu].policy; >+ policy->max_cpu_freq = cpufreq_driver->policy[cpu].max_cpu_freq; >+ policy->cpu = cpu; >+ >+ up(&cpufreq_driver_sem); >+ >+ return 0; >+} >+EXPORT_SYMBOL(cpufreq_get_policy); >+ >+ >+/** >+ * cpufreq_set_policy - set a new CPUFreq policy >+ * @policy: policy to be set. >+ * >+ * Sets a new CPU frequency and voltage scaling policy. >+ */ >+int cpufreq_set_policy(struct cpufreq_policy *policy) >+{ >+ unsigned int i; >+ int ret; >+ >+ down(&cpufreq_driver_sem); >+ if (!cpufreq_driver || !cpufreq_driver->verify || >+ !cpufreq_driver->setpolicy || !policy || >+ (policy->cpu > NR_CPUS)) { >+ up(&cpufreq_driver_sem); >+ return -EINVAL; >+ } >+ >+ if (policy->cpu == CPUFREQ_ALL_CPUS) >+ policy->max_cpu_freq = cpufreq_driver->policy[0].max_cpu_freq; >+ else >+ policy->max_cpu_freq = cpufreq_driver->policy[policy->cpu].max_cpu_freq; >+ >+ >+ /* verify the cpu speed can be set within this limit */ >+ ret = cpufreq_driver->verify(policy); >+ if (ret) { >+ up(&cpufreq_driver_sem); >+ return ret; >+ } >+ >+ down(&cpufreq_notifier_sem); >+ >+ /* adjust if neccessary - all reasons */ >+ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, >+ policy); >+ >+ /* adjust if neccessary - hardware incompatibility*/ >+ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE, >+ policy); >+ >+ /* verify the cpu speed can be set within this limit, >+ which might be different to the first one */ >+ ret = cpufreq_driver->verify(policy); >+ if (ret) { >+ up(&cpufreq_notifier_sem); >+ up(&cpufreq_driver_sem); >+ return ret; >+ } >+ >+ /* notification of the new policy */ >+ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, >+ policy); >+ >+ up(&cpufreq_notifier_sem); >+ >+ if (policy->cpu == CPUFREQ_ALL_CPUS) { >+ for (i=0;i<NR_CPUS;i++) { >+ cpufreq_driver->policy[i].min = policy->min; >+ cpufreq_driver->policy[i].max = policy->max; >+ cpufreq_driver->policy[i].policy = policy->policy; >+ } >+ } else { >+ cpufreq_driver->policy[policy->cpu].min = policy->min; >+ cpufreq_driver->policy[policy->cpu].max = policy->max; >+ cpufreq_driver->policy[policy->cpu].policy = policy->policy; >+ } >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+ if (policy->cpu == CPUFREQ_ALL_CPUS) { >+ for (i=0;i<NR_CPUS;i++) >+ cpu_cur_freq[i] = policy->max; >+ } else >+ cpu_cur_freq[policy->cpu] = policy->max; >+#endif >+ >+ ret = cpufreq_driver->setpolicy(policy); >+ >+ up(&cpufreq_driver_sem); >+ >+ return ret; >+} >+EXPORT_SYMBOL(cpufreq_set_policy); >+ >+ >+ >+/********************************************************************* >+ * DYNAMIC CPUFREQ SWITCHING * >+ *********************************************************************/ >+#ifdef CONFIG_CPU_FREQ_DYNAMIC >+/* TBD */ >+#endif /* CONFIG_CPU_FREQ_DYNAMIC */ >+ >+ >+ >+/********************************************************************* >+ * EXTERNALLY AFFECTING FREQUENCY CHANGES * >+ *********************************************************************/ >+ >+/** >+ * adjust_jiffies - adjust the system "loops_per_jiffy" >+ * >+ * This function alters the system "loops_per_jiffy" for the clock >+ * speed change. Note that loops_per_jiffy is only updated if all >+ * CPUs are affected - else there is a need for per-CPU loops_per_jiffy >+ * values which are provided by various architectures. >+ */ >+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) >+{ >+ if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || >+ (val == CPUFREQ_POSTCHANGE && ci->old > ci->new)) >+ if (ci->cpu == CPUFREQ_ALL_CPUS) >+ loops_per_jiffy = cpufreq_scale(loops_per_jiffy, ci->old, ci->new); >+} >+ >+ >+/** >+ * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition >+ * >+ * This function calls the transition notifiers and the "adjust_jiffies" function. It is called >+ * twice on all CPU frequency changes that have external effects. >+ */ >+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) >+{ >+ down(&cpufreq_notifier_sem); >+ switch (state) { >+ case CPUFREQ_PRECHANGE: >+ notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); >+ adjust_jiffies(CPUFREQ_PRECHANGE, freqs); >+ break; >+ case CPUFREQ_POSTCHANGE: >+ adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); >+ notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); >+#ifdef CONFIG_CPU_FREQ_24_API >+ if (freqs->cpu == CPUFREQ_ALL_CPUS) { >+ int i; >+ for (i=0;i<NR_CPUS;i++) >+ cpu_cur_freq[i] = freqs->new; >+ } else >+ cpu_cur_freq[freqs->cpu] = freqs->new; >+#endif >+ break; >+ } >+ up(&cpufreq_notifier_sem); >+} >+EXPORT_SYMBOL_GPL(cpufreq_notify_transition); >+ >+ >+ >+/********************************************************************* >+ * REGISTER / UNREGISTER CPUFREQ DRIVER * >+ *********************************************************************/ >+ >+/** >+ * cpufreq_register - register a CPU Frequency driver >+ * @driver_data: A struct cpufreq_driver containing the values submitted by the CPU Frequency driver. >+ * >+ * Registers a CPU Frequency driver to this core code. This code >+ * returns zero on success, -EBUSY when another driver got here first >+ * (and isn't unregistered in the meantime). >+ * >+ */ >+int cpufreq_register(struct cpufreq_driver *driver_data) >+{ >+ unsigned int ret; >+ unsigned int i; >+ struct cpufreq_policy policy; >+ >+ if (cpufreq_driver) >+ return -EBUSY; >+ >+ if (!driver_data || !driver_data->verify || >+ !driver_data->setpolicy) >+ return -EINVAL; >+ >+ down(&cpufreq_driver_sem); >+ cpufreq_driver = driver_data; >+ >+ /* check for a default policy - if it exists, use it on _all_ CPUs*/ >+ for (i=0; i<NR_CPUS; i++) >+ { >+ if (default_policy.policy) >+ cpufreq_driver->policy[i].policy = default_policy.policy; >+ if (default_policy.min) >+ cpufreq_driver->policy[i].min = default_policy.min; >+ if (default_policy.max) >+ cpufreq_driver->policy[i].max = default_policy.max; >+ } >+ >+ /* set default policy on all CPUs. Must be called per-CPU and not >+ * with CPUFREQ_ALL_CPUs as there might be no common policy for all >+ * CPUs (UltraSPARC etc.) >+ */ >+ for (i=0; i<NR_CPUS; i++) >+ { >+ policy.policy = cpufreq_driver->policy[i].policy; >+ policy.min = cpufreq_driver->policy[i].min; >+ policy.max = cpufreq_driver->policy[i].max; >+ policy.cpu = i; >+ up(&cpufreq_driver_sem); >+ ret = cpufreq_set_policy(&policy); >+ down(&cpufreq_driver_sem); >+ if (ret) { >+ cpufreq_driver = NULL; >+ up(&cpufreq_driver_sem); >+ return ret; >+ } >+ } >+ >+ up(&cpufreq_driver_sem); >+ >+ cpufreq_proc_init(); >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+ down(&cpufreq_driver_sem); >+ for (i=0; i<NR_CPUS; i++) >+ { >+ cpu_min_freq[i] = driver_data->cpu_min_freq[i]; >+ cpu_max_freq[i] = driver_data->policy[i].max_cpu_freq; >+ cpu_cur_freq[i] = driver_data->cpu_cur_freq[i]; >+ } >+ up(&cpufreq_driver_sem); >+ >+ cpufreq_sysctl_init(); >+#endif >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(cpufreq_register); >+ >+ >+/** >+ * cpufreq_unregister - unregister the current CPUFreq driver >+ * >+ * Unregister the current CPUFreq driver. Only call this if you have >+ * the right to do so, i.e. if you have succeeded in initialising before! >+ * Returns zero if successful, and -EINVAL if the cpufreq_driver is >+ * currently not initialised. >+ */ >+int cpufreq_unregister(void) >+{ >+ down(&cpufreq_driver_sem); >+ >+ if (!cpufreq_driver) { >+ up(&cpufreq_driver_sem); >+ return -EINVAL; >+ } >+ >+ cpufreq_driver = NULL; >+ >+ up(&cpufreq_driver_sem); >+ >+ cpufreq_proc_exit(); >+ >+#ifdef CONFIG_CPU_FREQ_24_API >+ cpufreq_sysctl_exit(); >+#endif >+ >+ return 0; >+} >+EXPORT_SYMBOL_GPL(cpufreq_unregister); >+ >+ >+#ifdef CONFIG_PM >+/** >+ * cpufreq_restore - restore the CPU clock frequency after resume >+ * >+ * Restore the CPU clock frequency so that our idea of the current >+ * frequency reflects the actual hardware. >+ */ >+int cpufreq_restore(void) >+{ >+ struct cpufreq_policy policy; >+ unsigned int i; >+ unsigned int ret = 0; >+ >+ if (in_interrupt()) >+ panic("cpufreq_restore() called from interrupt context!"); >+ >+ for (i=0;i<NR_CPUS;i++) { >+ if (!cpu_online(i)) >+ continue; >+ >+ down(&cpufreq_driver_sem); >+ if (!cpufreq_driver) { >+ up(&cpufreq_driver_sem); >+ return 0; >+ } >+ >+ policy.min = cpufreq_driver->policy[i].min; >+ policy.max = cpufreq_driver->policy[i].max; >+ policy.policy = cpufreq_driver->policy[i].policy; >+ policy.cpu = i; >+ up(&cpufreq_driver_sem); >+ >+ ret += cpufreq_set_policy(&policy); >+ } >+ >+ return ret; >+} >+EXPORT_SYMBOL_GPL(cpufreq_restore); >+#else >+#define cpufreq_restore() >+#endif /* CONFIG_PM */ >+ >diff -Naur linux-2.4.22-ppc-dev.orig/kernel/panic.c linux-2.4.22-ppc-dev/kernel/panic.c >--- linux-2.4.22-ppc-dev.orig/kernel/panic.c 2002-11-29 00:53:15.000000000 +0100 >+++ linux-2.4.22-ppc-dev/kernel/panic.c 2003-08-25 23:37:48.000000000 +0200 >@@ -48,6 +48,10 @@ > #if defined(CONFIG_ARCH_S390) > unsigned long caller = (unsigned long) __builtin_return_address(0); > #endif >+#ifdef CONFIG_BOOTX_TEXT >+ extern int force_printk_to_btext; >+ force_printk_to_btext = 1; >+#endif > > bust_spinlocks(1); > va_start(args, fmt); >diff -Naur linux-2.4.22-ppc-dev.orig/kernel/printk.c linux-2.4.22-ppc-dev/kernel/printk.c >--- linux-2.4.22-ppc-dev.orig/kernel/printk.c 2003-08-27 15:18:15.000000000 +0200 >+++ linux-2.4.22-ppc-dev/kernel/printk.c 2003-08-25 23:37:54.000000000 +0200 >@@ -26,7 +26,9 @@ > #include <linux/module.h> > #include <linux/interrupt.h> /* For in_interrupt() */ > #include <linux/config.h> >- >+#ifdef CONFIG_BOOTX_TEXT >+#include <asm/btext.h> >+#endif > #include <asm/uaccess.h> > > #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) >@@ -412,6 +414,9 @@ > char *p; > static char printk_buf[1024]; > static int log_level_unknown = 1; >+#ifdef CONFIG_BOOTX_TEXT >+ extern int force_printk_to_btext; >+#endif > > if (oops_in_progress) { > /* If a crash is occurring, make sure we can't deadlock */ >@@ -427,7 +432,10 @@ > va_start(args, fmt); > printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); > va_end(args); >- >+#ifdef CONFIG_BOOTX_TEXT >+ if (force_printk_to_btext) >+ btext_drawstring(printk_buf); >+#endif /* CONFIG_BOOTX_TEXT */ > /* > * Copy the output into log_buf. If the caller didn't provide > * appropriate log level tags, we insert them here >diff -Naur linux-2.4.22-ppc-dev.orig/kernel/resource.c linux-2.4.22-ppc-dev/kernel/resource.c >--- linux-2.4.22-ppc-dev.orig/kernel/resource.c 2002-11-29 00:53:15.000000000 +0100 >+++ linux-2.4.22-ppc-dev/kernel/resource.c 2003-08-25 23:37:55.000000000 +0200 >@@ -118,6 +118,11 @@ > write_lock(&resource_lock); > conflict = __request_resource(root, new); > write_unlock(&resource_lock); >+ if (conflict) { >+ printk("resource conflict with: %lx..%lx (%lx), name: %s\n", >+ conflict->start, conflict->end, conflict->flags, >+ conflict->name ? conflict->name : "<NULL>"); >+ } > return conflict ? -EBUSY : 0; > } > >diff -Naur linux-2.4.22-ppc-dev.orig/kernel/sysctl.c linux-2.4.22-ppc-dev/kernel/sysctl.c >--- linux-2.4.22-ppc-dev.orig/kernel/sysctl.c 2003-08-27 15:18:15.000000000 +0200 >+++ linux-2.4.22-ppc-dev/kernel/sysctl.c 2003-08-25 23:37:51.000000000 +0200 >@@ -51,6 +51,8 @@ > extern int core_uses_pid; > extern char core_pattern[]; > extern int cad_pid; >+extern int laptop_mode; >+extern int block_dump; > > /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ > static int maxolduid = 65535; >@@ -284,12 +286,18 @@ > &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec}, > {VM_PAGE_CLUSTER, "page-cluster", > &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec}, >+ {VM_HEAP_STACK_GAP, "heap-stack-gap", >+ &heap_stack_gap, sizeof(int), 0644, NULL, &proc_dointvec}, > {VM_MIN_READAHEAD, "min-readahead", > &vm_min_readahead,sizeof(int), 0644, NULL, &proc_dointvec}, > {VM_MAX_READAHEAD, "max-readahead", > &vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec}, > {VM_MAX_MAP_COUNT, "max_map_count", > &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec}, >+ {VM_LAPTOP_MODE, "laptop_mode", >+ &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec}, >+ {VM_BLOCK_DUMP, "block_dump", >+ &block_dump, sizeof(int), 0644, NULL, &proc_dointvec}, > {0} > }; > >diff -Naur linux-2.4.22-ppc-dev.orig/mm/filemap.c linux-2.4.22-ppc-dev/mm/filemap.c >--- linux-2.4.22-ppc-dev.orig/mm/filemap.c 2003-08-27 15:18:15.000000000 +0200 >+++ linux-2.4.22-ppc-dev/mm/filemap.c 2003-08-25 23:37:30.000000000 +0200 >@@ -165,6 +165,8 @@ > > if (mapping && mapping->host) > mark_inode_dirty_pages(mapping->host); >+ if (block_dump) >+ printk("%s: dirtied page\n", current->comm); > } > } > } >diff -Naur linux-2.4.22-ppc-dev.orig/mm/mmap.c linux-2.4.22-ppc-dev/mm/mmap.c >--- linux-2.4.22-ppc-dev.orig/mm/mmap.c 2003-06-13 16:51:39.000000000 +0200 >+++ linux-2.4.22-ppc-dev/mm/mmap.c 2003-08-25 23:37:46.000000000 +0200 >@@ -45,6 +45,7 @@ > }; > > int sysctl_overcommit_memory; >+int heap_stack_gap = 1; > int max_map_count = DEFAULT_MAX_MAP_COUNT; > > /* Check that a process has enough memory to allocate a >@@ -630,9 +631,15 @@ > > for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { > /* At this point: (!vma || addr < vma->vm_end). */ >+ unsigned long __heap_stack_gap; > if (TASK_SIZE - len < addr) > return -ENOMEM; >- if (!vma || addr + len <= vma->vm_start) >+ if (!vma) >+ return addr; >+ __heap_stack_gap = 0; >+ if (vma->vm_flags & VM_GROWSDOWN) >+ __heap_stack_gap = heap_stack_gap << PAGE_SHIFT; >+ if (addr + len + __heap_stack_gap <= vma->vm_start) > return addr; > addr = vma->vm_end; > } >@@ -741,7 +748,7 @@ > > struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr) > { >- struct vm_area_struct * vma; >+ struct vm_area_struct * vma, * prev_vma; > unsigned long start; > > addr &= PAGE_MASK; >@@ -753,7 +760,8 @@ > if (!(vma->vm_flags & VM_GROWSDOWN)) > return NULL; > start = vma->vm_start; >- if (expand_stack(vma, addr)) >+ find_vma_prev(mm, addr, &prev_vma); >+ if (expand_stack(vma, addr, prev_vma)) > return NULL; > if (vma->vm_flags & VM_LOCKED) { > make_pages_present(addr, start);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 27558
:
16776
|
16777
|
16778
|
16779
|
16780
|
16781
|
16953
|
17123