summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-acpi127
-rw-r--r--Documentation/i2c/chips/max68752
-rw-r--r--Documentation/i2c/chips/pca953910
-rw-r--r--Documentation/i2c/chips/pcf857412
-rw-r--r--Documentation/i2c/chips/pcf85759
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--Documentation/laptops/acer-wmi.txt2
-rw-r--r--MAINTAINERS25
-rw-r--r--Makefile4
-rw-r--r--arch/ia64/kernel/process.c4
-rw-r--r--arch/powerpc/platforms/82xx/ep8248e.c4
-rw-r--r--arch/x86/kernel/acpi/processor.c6
-rw-r--r--arch/x86/kernel/process.c28
-rw-r--r--arch/x86/mm/srat_32.c3
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/bay.c3
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/dispatcher/dsinit.c2
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c1
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c22
-rw-r--r--drivers/acpi/dispatcher/dswexec.c8
-rw-r--r--drivers/acpi/dispatcher/dswstate.c20
-rw-r--r--drivers/acpi/dock.c3
-rw-r--r--drivers/acpi/events/evevent.c6
-rw-r--r--drivers/acpi/events/evgpe.c36
-rw-r--r--drivers/acpi/events/evgpeblk.c18
-rw-r--r--drivers/acpi/events/evmisc.c4
-rw-r--r--drivers/acpi/events/evregion.c5
-rw-r--r--drivers/acpi/events/evrgnini.c2
-rw-r--r--drivers/acpi/events/evxfevnt.c18
-rw-r--r--drivers/acpi/executer/exconfig.c17
-rw-r--r--drivers/acpi/executer/exconvrt.c12
-rw-r--r--drivers/acpi/executer/excreate.c2
-rw-r--r--drivers/acpi/executer/exdump.c67
-rw-r--r--drivers/acpi/executer/exfldio.c9
-rw-r--r--drivers/acpi/executer/exmisc.c8
-rw-r--r--drivers/acpi/executer/exprep.c8
-rw-r--r--drivers/acpi/executer/exregion.c2
-rw-r--r--drivers/acpi/executer/exresop.c4
-rw-r--r--drivers/acpi/executer/exstore.c6
-rw-r--r--drivers/acpi/fan.c8
-rw-r--r--drivers/acpi/glue.c3
-rw-r--r--drivers/acpi/hardware/hwgpe.c52
-rw-r--r--drivers/acpi/namespace/nsdump.c6
-rw-r--r--drivers/acpi/namespace/nseval.c35
-rw-r--r--drivers/acpi/namespace/nsinit.c1
-rw-r--r--drivers/acpi/namespace/nsload.c3
-rw-r--r--drivers/acpi/namespace/nsparse.c15
-rw-r--r--drivers/acpi/namespace/nsutils.c50
-rw-r--r--drivers/acpi/namespace/nsxfeval.c3
-rw-r--r--drivers/acpi/numa.c4
-rw-r--r--drivers/acpi/parser/psargs.c4
-rw-r--r--drivers/acpi/parser/psxface.c4
-rw-r--r--drivers/acpi/pci_irq.c38
-rw-r--r--drivers/acpi/processor_core.c75
-rw-r--r--drivers/acpi/processor_idle.c34
-rw-r--r--drivers/acpi/processor_perflib.c18
-rw-r--r--drivers/acpi/processor_throttling.c38
-rw-r--r--drivers/acpi/reboot.c50
-rw-r--r--drivers/acpi/resources/rscalc.c4
-rw-r--r--drivers/acpi/resources/rscreate.c41
-rw-r--r--drivers/acpi/resources/rsmisc.c2
-rw-r--r--drivers/acpi/resources/rsutils.c13
-rw-r--r--drivers/acpi/scan.c62
-rw-r--r--drivers/acpi/sleep/main.c39
-rw-r--r--drivers/acpi/system.c169
-rw-r--r--drivers/acpi/tables/tbfadt.c23
-rw-r--r--drivers/acpi/tables/tbfind.c5
-rw-r--r--drivers/acpi/tables/tbinstal.c30
-rw-r--r--drivers/acpi/tables/tbutils.c15
-rw-r--r--drivers/acpi/tables/tbxface.c28
-rw-r--r--drivers/acpi/tables/tbxfroot.c4
-rw-r--r--drivers/acpi/utilities/utalloc.c5
-rw-r--r--drivers/acpi/utilities/utcopy.c4
-rw-r--r--drivers/acpi/utilities/utdebug.c54
-rw-r--r--drivers/acpi/utilities/utdelete.c2
-rw-r--r--drivers/acpi/utilities/uteval.c5
-rw-r--r--drivers/acpi/utilities/utmisc.c39
-rw-r--r--drivers/acpi/utilities/utmutex.c4
-rw-r--r--drivers/acpi/utilities/utobject.c9
-rw-r--r--drivers/acpi/video.c123
-rw-r--r--drivers/char/apm-emulation.c346
-rw-r--r--drivers/hwmon/ad7418.c109
-rw-r--r--drivers/hwmon/adm1021.c105
-rw-r--r--drivers/hwmon/adm1025.c101
-rw-r--r--drivers/hwmon/adm1026.c109
-rw-r--r--drivers/hwmon/adm1029.c97
-rw-r--r--drivers/hwmon/adm1031.c96
-rw-r--r--drivers/hwmon/adm9240.c93
-rw-r--r--drivers/hwmon/ads7828.c89
-rw-r--r--drivers/hwmon/adt7470.c100
-rw-r--r--drivers/hwmon/adt7473.c102
-rw-r--r--drivers/hwmon/asb100.c207
-rw-r--r--drivers/hwmon/atxp1.c109
-rw-r--r--drivers/hwmon/ds1621.c99
-rw-r--r--drivers/hwmon/f75375s.c89
-rw-r--r--drivers/hwmon/fscher.c93
-rw-r--r--drivers/hwmon/fschmd.c112
-rw-r--r--drivers/hwmon/fscpos.c94
-rw-r--r--drivers/hwmon/gl518sm.c99
-rw-r--r--drivers/hwmon/gl520sm.c91
-rw-r--r--drivers/hwmon/lm63.c99
-rw-r--r--drivers/hwmon/lm77.c102
-rw-r--r--drivers/hwmon/lm80.c94
-rw-r--r--drivers/hwmon/lm83.c104
-rw-r--r--drivers/hwmon/lm87.c99
-rw-r--r--drivers/hwmon/lm90.c119
-rw-r--r--drivers/hwmon/lm92.c98
-rw-r--r--drivers/hwmon/lm93.c126
-rw-r--r--drivers/hwmon/max1619.c101
-rw-r--r--drivers/hwmon/max6650.c102
-rw-r--r--drivers/hwmon/smsc47m192.c102
-rw-r--r--drivers/hwmon/thmc50.c107
-rw-r--r--drivers/hwmon/w83791d.c205
-rw-r--r--drivers/hwmon/w83792d.c214
-rw-r--r--drivers/hwmon/w83793.c227
-rw-r--r--drivers/hwmon/w83l785ts.c117
-rw-r--r--drivers/hwmon/w83l786ng.c98
-rw-r--r--drivers/i2c/busses/i2c-amd756-s4882.c27
-rw-r--r--drivers/i2c/busses/i2c-nforce2-s4985.c31
-rw-r--r--drivers/i2c/chips/eeprom.c92
-rw-r--r--drivers/i2c/chips/max6875.c120
-rw-r--r--drivers/i2c/chips/pca9539.c109
-rw-r--r--drivers/i2c/chips/pcf8574.c108
-rw-r--r--drivers/i2c/chips/pcf8575.c96
-rw-r--r--drivers/i2c/chips/pcf8591.c94
-rw-r--r--drivers/i2c/i2c-core.c4
-rw-r--r--drivers/misc/Kconfig31
-rw-r--r--drivers/misc/Makefile5
-rw-r--r--drivers/misc/acer-wmi.c145
-rw-r--r--drivers/misc/compal-laptop.c404
-rw-r--r--drivers/misc/eeepc-laptop.c4
-rw-r--r--drivers/misc/fujitsu-laptop.c825
-rw-r--r--drivers/pci/pci-acpi.c6
-rw-r--r--drivers/pci/pci.c4
-rw-r--r--drivers/pci/pci.h3
-rw-r--r--drivers/pnp/base.h148
-rw-r--r--drivers/pnp/core.c29
-rw-r--r--drivers/pnp/interface.c207
-rw-r--r--drivers/pnp/isapnp/core.c253
-rw-r--r--drivers/pnp/manager.c414
-rw-r--r--drivers/pnp/pnpacpi/core.c4
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c492
-rw-r--r--drivers/pnp/pnpbios/rsparser.c274
-rw-r--r--drivers/pnp/quirks.c307
-rw-r--r--drivers/pnp/resource.c454
-rw-r--r--drivers/pnp/support.c171
-rw-r--r--drivers/pnp/system.c4
-rw-r--r--drivers/serial/8250_pnp.c24
-rw-r--r--drivers/w1/masters/ds2482.c104
-rw-r--r--firmware/.gitignore6
-rw-r--r--firmware/Makefile2
-rw-r--r--fs/Kconfig136
-rw-r--r--fs/compat_ioctl.c6
-rw-r--r--fs/lockd/clntproc.c8
-rw-r--r--fs/lockd/svc4proc.c2
-rw-r--r--fs/lockd/svclock.c7
-rw-r--r--fs/lockd/svcproc.c2
-rw-r--r--fs/nfs/callback.c34
-rw-r--r--fs/nfs/client.c13
-rw-r--r--fs/nfs/dir.c88
-rw-r--r--fs/nfs/direct.c4
-rw-r--r--fs/nfs/file.c155
-rw-r--r--fs/nfs/inode.c79
-rw-r--r--fs/nfs/internal.h1
-rw-r--r--fs/nfs/iostat.h119
-rw-r--r--fs/nfs/nfs3acl.c9
-rw-r--r--fs/nfs/nfs3proc.c275
-rw-r--r--fs/nfs/nfs4proc.c265
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfs/nfsroot.c10
-rw-r--r--fs/nfs/proc.c28
-rw-r--r--fs/nfs/super.c882
-rw-r--r--fs/nfs/write.c322
-rw-r--r--fs/nfsd/nfs4callback.c2
-rw-r--r--include/acpi/acconfig.h2
-rw-r--r--include/acpi/acdisasm.h1
-rw-r--r--include/acpi/acdispat.h2
-rw-r--r--include/acpi/acexcep.h10
-rw-r--r--include/acpi/acglobal.h2
-rw-r--r--include/acpi/achware.h4
-rw-r--r--include/acpi/acinterp.h5
-rw-r--r--include/acpi/aclocal.h6
-rw-r--r--include/acpi/acmacros.h38
-rw-r--r--include/acpi/acnamesp.h30
-rw-r--r--include/acpi/acpi_bus.h4
-rw-r--r--include/acpi/acpiosxf.h2
-rw-r--r--include/acpi/acpixf.h12
-rw-r--r--include/acpi/acstruct.h10
-rw-r--r--include/acpi/actables.h27
-rw-r--r--include/acpi/actbl1.h23
-rw-r--r--include/acpi/actypes.h16
-rw-r--r--include/acpi/acutils.h70
-rw-r--r--include/acpi/processor.h2
-rw-r--r--include/acpi/reboot.h14
-rw-r--r--include/asm-ia64/processor.h2
-rw-r--r--include/asm-x86/processor.h2
-rw-r--r--include/linux/blkdev.h3
-rw-r--r--include/linux/freezer.h10
-rw-r--r--include/linux/inet.h7
-rw-r--r--include/linux/ioport.h5
-rw-r--r--include/linux/nfs_fs.h10
-rw-r--r--include/linux/nfs_iostat.h119
-rw-r--r--include/linux/nfs_page.h9
-rw-r--r--include/linux/nfs_xdr.h3
-rw-r--r--include/linux/pnp.h146
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/sunrpc/clnt.h7
-rw-r--r--include/linux/sunrpc/sched.h1
-rw-r--r--kernel/cpu.c1
-rw-r--r--kernel/kthread.c2
-rw-r--r--kernel/power/process.c97
-rw-r--r--kernel/power/user.c71
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c27
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c4
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c4
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_token.c2
-rw-r--r--net/sunrpc/auth_unix.c2
-rw-r--r--net/sunrpc/clnt.c161
-rw-r--r--net/sunrpc/rpcb_clnt.c356
-rw-r--r--net/sunrpc/sched.c23
-rw-r--r--net/sunrpc/xprt.c9
-rw-r--r--net/sunrpc/xprtsock.c2
223 files changed, 8425 insertions, 6494 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
index 9470ed9afcc..f27be7d1a49 100644
--- a/Documentation/ABI/testing/sysfs-firmware-acpi
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -29,46 +29,46 @@ Description:
$ cd /sys/firmware/acpi/interrupts
$ grep . *
- error:0
- ff_gbl_lock:0
- ff_pmtimer:0
- ff_pwr_btn:0
- ff_rt_clk:0
- ff_slp_btn:0
- gpe00:0
- gpe01:0
- gpe02:0
- gpe03:0
- gpe04:0
- gpe05:0
- gpe06:0
- gpe07:0
- gpe08:0
- gpe09:174
- gpe0A:0
- gpe0B:0
- gpe0C:0
- gpe0D:0
- gpe0E:0
- gpe0F:0
- gpe10:0
- gpe11:60
- gpe12:0
- gpe13:0
- gpe14:0
- gpe15:0
- gpe16:0
- gpe17:0
- gpe18:0
- gpe19:7
- gpe1A:0
- gpe1B:0
- gpe1C:0
- gpe1D:0
- gpe1E:0
- gpe1F:0
- gpe_all:241
- sci:241
+ error: 0
+ ff_gbl_lock: 0 enable
+ ff_pmtimer: 0 invalid
+ ff_pwr_btn: 0 enable
+ ff_rt_clk: 2 disable
+ ff_slp_btn: 0 invalid
+ gpe00: 0 invalid
+ gpe01: 0 enable
+ gpe02: 108 enable
+ gpe03: 0 invalid
+ gpe04: 0 invalid
+ gpe05: 0 invalid
+ gpe06: 0 enable
+ gpe07: 0 enable
+ gpe08: 0 invalid
+ gpe09: 0 invalid
+ gpe0A: 0 invalid
+ gpe0B: 0 invalid
+ gpe0C: 0 invalid
+ gpe0D: 0 invalid
+ gpe0E: 0 invalid
+ gpe0F: 0 invalid
+ gpe10: 0 invalid
+ gpe11: 0 invalid
+ gpe12: 0 invalid
+ gpe13: 0 invalid
+ gpe14: 0 invalid
+ gpe15: 0 invalid
+ gpe16: 0 invalid
+ gpe17: 1084 enable
+ gpe18: 0 enable
+ gpe19: 0 invalid
+ gpe1A: 0 invalid
+ gpe1B: 0 invalid
+ gpe1C: 0 invalid
+ gpe1D: 0 invalid
+ gpe1E: 0 invalid
+ gpe1F: 0 invalid
+ gpe_all: 1192
+ sci: 1194
sci - The total number of times the ACPI SCI
has claimed an interrupt.
@@ -89,6 +89,13 @@ Description:
error - an interrupt that can't be accounted for above.
+ invalid: it's either a wakeup GPE or a GPE/Fixed Event that
+ doesn't have an event handler.
+
+ disable: the GPE/Fixed Event is valid but disabled.
+
+ enable: the GPE/Fixed Event is valid and enabled.
+
Root has permission to clear any of these counters. Eg.
# echo 0 > gpe11
@@ -97,3 +104,43 @@ Description:
None of these counters has an effect on the function
of the system, they are simply statistics.
+
+ Besides this, user can also write specific strings to these files
+ to enable/disable/clear ACPI interrupts in user space, which can be
+ used to debug some ACPI interrupt storm issues.
+
+ Note that only writting to VALID GPE/Fixed Event is allowed,
+ i.e. user can only change the status of runtime GPE and
+ Fixed Event with event handler installed.
+
+ Let's take power button fixed event for example, please kill acpid
+ and other user space applications so that the machine won't shutdown
+ when pressing the power button.
+ # cat ff_pwr_btn
+ 0
+ # press the power button for 3 times;
+ # cat ff_pwr_btn
+ 3
+ # echo disable > ff_pwr_btn
+ # cat ff_pwr_btn
+ disable
+ # press the power button for 3 times;
+ # cat ff_pwr_btn
+ disable
+ # echo enable > ff_pwr_btn
+ # cat ff_pwr_btn
+ 4
+ /*
+ * this is because the status bit is set even if the enable bit is cleared,
+ * and it triggers an ACPI fixed event when the enable bit is set again
+ */
+ # press the power button for 3 times;
+ # cat ff_pwr_btn
+ 7
+ # echo disable > ff_pwr_btn
+ # press the power button for 3 times;
+ # echo clear > ff_pwr_btn /* clear the status bit */
+ # echo disable > ff_pwr_btn
+ # cat ff_pwr_btn
+ 7
+
diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875
index a0cd8af2f40..10ca43cd1a7 100644
--- a/Documentation/i2c/chips/max6875
+++ b/Documentation/i2c/chips/max6875
@@ -49,7 +49,7 @@ $ modprobe max6875 force=0,0x50
The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
addresses. For example, for address 0x50, it also reserves 0x51.
-The even-address instance is called 'max6875', the odd one is 'max6875 subclient'.
+The even-address instance is called 'max6875', the odd one is 'dummy'.
Programming the chip using i2c-dev
diff --git a/Documentation/i2c/chips/pca9539 b/Documentation/i2c/chips/pca9539
index 1d81c530c4a..6aff890088b 100644
--- a/Documentation/i2c/chips/pca9539
+++ b/Documentation/i2c/chips/pca9539
@@ -7,7 +7,7 @@ drivers/gpio/pca9539.c instead.
Supported chips:
* Philips PCA9539
Prefix: 'pca9539'
- Addresses scanned: 0x74 - 0x77
+ Addresses scanned: none
Datasheet:
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf
@@ -23,6 +23,14 @@ The input sense can also be inverted.
The 16 lines are split between two bytes.
+Detection
+---------
+
+The PCA9539 is difficult to detect and not commonly found in PC machines,
+so you have to pass the I2C bus and address of the installed PCA9539
+devices explicitly to the driver at load time via the force=... parameter.
+
+
Sysfs entries
-------------
diff --git a/Documentation/i2c/chips/pcf8574 b/Documentation/i2c/chips/pcf8574
index 5c1ad1376b6..235815c075f 100644
--- a/Documentation/i2c/chips/pcf8574
+++ b/Documentation/i2c/chips/pcf8574
@@ -4,13 +4,13 @@ Kernel driver pcf8574
Supported chips:
* Philips PCF8574
Prefix: 'pcf8574'
- Addresses scanned: I2C 0x20 - 0x27
+ Addresses scanned: none
Datasheet: Publicly available at the Philips Semiconductors website
http://www.semiconductors.philips.com/pip/PCF8574P.html
* Philips PCF8574A
Prefix: 'pcf8574a'
- Addresses scanned: I2C 0x38 - 0x3f
+ Addresses scanned: none
Datasheet: Publicly available at the Philips Semiconductors website
http://www.semiconductors.philips.com/pip/PCF8574P.html
@@ -38,12 +38,10 @@ For more informations see the datasheet.
Accessing PCF8574(A) via /sys interface
-------------------------------------
-! Be careful !
The PCF8574(A) is plainly impossible to detect ! Stupid chip.
-So every chip with address in the interval [20..27] and [38..3f] are
-detected as PCF8574(A). If you have other chips in this address
-range, the workaround is to load this module after the one
-for your others chips.
+So, you have to pass the I2C bus and address of the installed PCF857A
+and PCF8574A devices explicitly to the driver at load time via the
+force=... parameter.
On detection (i.e. insmod, modprobe et al.), directories are being
created for each detected PCF8574(A):
diff --git a/Documentation/i2c/chips/pcf8575 b/Documentation/i2c/chips/pcf8575
index 25f5698a61c..40b268eb276 100644
--- a/Documentation/i2c/chips/pcf8575
+++ b/Documentation/i2c/chips/pcf8575
@@ -40,12 +40,9 @@ Detection
---------
There is no method known to detect whether a chip on a given I2C address is
-a PCF8575 or whether it is any other I2C device. So there are two alternatives
-to let the driver find the installed PCF8575 devices:
-- Load this driver after any other I2C driver for I2C devices with addresses
- in the range 0x20 .. 0x27.
-- Pass the I2C bus and address of the installed PCF8575 devices explicitly to
- the driver at load time via the probe=... or force=... parameters.
+a PCF8575 or whether it is any other I2C device, so you have to pass the I2C
+bus and address of the installed PCF8575 devices explicitly to the driver at
+load time via the force=... parameter.
/sys interface
--------------
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 312fe77764a..5e497d16fb5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -818,7 +818,7 @@ and is between 256 and 4096 characters. It is defined in the file
See Documentation/ide/ide.txt.
idle= [X86]
- Format: idle=poll or idle=mwait
+ Format: idle=poll or idle=mwait, idle=halt, idle=nomwait
Poll forces a polling idle loop that can slightly improves the performance
of waking up a idle CPU, but will use a lot of power and make the system
run hot. Not recommended.
@@ -826,6 +826,9 @@ and is between 256 and 4096 characters. It is defined in the file
to not use it because it doesn't save as much power as a normal idle
loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
as idle=poll.
+ idle=halt. Halt is forced to be used for CPU idle.
+ In such case C2/C3 won't be used again.
+ idle=nomwait. Disable mwait for CPU C-states
ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
Claim all unknown PCI IDE storage controllers.
diff --git a/Documentation/laptops/acer-wmi.txt b/Documentation/laptops/acer-wmi.txt
index 79b7dbd2214..69b5dd4e5a5 100644
--- a/Documentation/laptops/acer-wmi.txt
+++ b/Documentation/laptops/acer-wmi.txt
@@ -174,8 +174,6 @@ The LED is exposed through the LED subsystem, and can be found in:
The mail LED is autodetected, so if you don't have one, the LED device won't
be registered.
-If you have a mail LED that is not green, please report this to me.
-
Backlight
*********
diff --git a/MAINTAINERS b/MAINTAINERS
index ee1c56a2075..633bda666e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -216,8 +216,8 @@ W: http://code.google.com/p/aceracpi
S: Maintained
ACPI
-P: Len Brown
-M: len.brown@intel.com
+P: Andi Kleen
+M: ak@linux.intel.com
M: lenb@kernel.org
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
@@ -239,8 +239,8 @@ W: http://www.lesswatts.org/projects/acpi/
S: Supported
ACPI FAN DRIVER
-P: Len Brown
-M: len.brown@intel.com
+P: Zhang Rui
+M: rui.zhang@intel.com
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
@@ -252,14 +252,14 @@ L: pcihpd-discuss@lists.sourceforge.net
S: Supported
ACPI THERMAL DRIVER
-P: Len Brown
-M: len.brown@intel.com
+P: Zhang Rui
+M: rui.zhang@intel.com
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Supported
ACPI VIDEO DRIVER
-P: Rui Zhang
+P: Zhang Rui
M: rui.zhang@intel.com
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
@@ -1160,6 +1160,11 @@ M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net
S: Supported
+COMPAL LAPTOP SUPPORT
+P: Cezary Jackiewicz
+M: cezary.jackiewicz@gmail.com
+S: Maintained
+
COMPUTONE INTELLIPORT MULTIPORT CARD
P: Michael H. Warfield
M: mhw@wittsend.com
@@ -1787,6 +1792,12 @@ P: David Howells
M: dhowells@redhat.com
S: Maintained
+FUJITSU LAPTOP EXTRAS
+P: Jonathan Woithe
+M: jwoithe@physics.adelaide.edu.au
+L: linux-acpi@vger.kernel.org
+S: Maintained
+
FUSE: FILESYSTEM IN USERSPACE
P: Miklos Szeredi
M: miklos@szeredi.hu
diff --git a/Makefile b/Makefile
index 8a2a275be30..1564577bdc5 100644
--- a/Makefile
+++ b/Makefile
@@ -508,6 +508,8 @@ else
KBUILD_CFLAGS += -O2
endif
+include $(srctree)/arch/$(SRCARCH)/Makefile
+
ifneq (CONFIG_FRAME_WARN,0)
KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
endif
@@ -516,8 +518,6 @@ endif
# Arch Makefiles may override this setting
KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
-include $(srctree)/arch/$(SRCARCH)/Makefile
-
ifdef CONFIG_FRAME_POINTER
KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
else
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index fabaf08d9a6..3ab8373103e 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -55,6 +55,10 @@ void (*ia64_mark_idle)(int);
unsigned long boot_option_idle_override = 0;
EXPORT_SYMBOL(boot_option_idle_override);
+unsigned long idle_halt;
+EXPORT_SYMBOL(idle_halt);
+unsigned long idle_nomwait;
+EXPORT_SYMBOL(idle_nomwait);
void
ia64_do_show_stack (struct unw_frame_info *info, void *arg)
diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c
index d5770fdf7f0..373e993a5ed 100644
--- a/arch/powerpc/platforms/82xx/ep8248e.c
+++ b/arch/powerpc/platforms/82xx/ep8248e.c
@@ -59,6 +59,7 @@ static void __init ep8248e_pic_init(void)
of_node_put(np);
}
+#ifdef CONFIG_FS_ENET_MDIO_FCC
static void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level)
{
if (level)
@@ -164,6 +165,7 @@ static struct of_platform_driver ep8248e_mdio_driver = {
.probe = ep8248e_mdio_probe,
.remove = ep8248e_mdio_remove,
};
+#endif
struct cpm_pin {
int port, pin, flags;
@@ -296,7 +298,9 @@ static __initdata struct of_device_id of_bus_ids[] = {
static int __init declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);
+#ifdef CONFIG_FS_ENET_MDIO_FCC
of_register_platform_driver(&ep8248e_mdio_driver);
+#endif
return 0;
}
diff --git a/arch/x86/kernel/acpi/processor.c b/arch/x86/kernel/acpi/processor.c
index de2d2e4ebad..7c074eec39f 100644
--- a/arch/x86/kernel/acpi/processor.c
+++ b/arch/x86/kernel/acpi/processor.c
@@ -56,6 +56,12 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
if (cpu_has(c, X86_FEATURE_ACPI))
buf[2] |= ACPI_PDC_T_FFH;
+ /*
+ * If mwait/monitor is unsupported, C2/C3_FFH will be disabled
+ */
+ if (!cpu_has(c, X86_FEATURE_MWAIT))
+ buf[2] &= ~(ACPI_PDC_C_C2C3_FFH);
+
obj->type = ACPI_TYPE_BUFFER;
obj->buffer.length = 12;
obj->buffer.pointer = (u8 *) buf;
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 7dceea94723..4d629c62f4f 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -7,6 +7,12 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/clockchips.h>
+#include <asm/system.h>
+
+unsigned long idle_halt;
+EXPORT_SYMBOL(idle_halt);
+unsigned long idle_nomwait;
+EXPORT_SYMBOL(idle_nomwait);
struct kmem_cache *task_xstate_cachep;
@@ -325,7 +331,27 @@ static int __init idle_setup(char *str)
pm_idle = poll_idle;
} else if (!strcmp(str, "mwait"))
force_mwait = 1;
- else
+ else if (!strcmp(str, "halt")) {
+ /*
+ * When the boot option of idle=halt is added, halt is
+ * forced to be used for CPU idle. In such case CPU C2/C3
+ * won't be used again.
+ * To continue to load the CPU idle driver, don't touch
+ * the boot_option_idle_override.
+ */
+ pm_idle = default_idle;
+ idle_halt = 1;
+ return 0;
+ } else if (!strcmp(str, "nomwait")) {
+ /*
+ * If the boot option of "idle=nomwait" is added,
+ * it means that mwait will be disabled for CPU C2/C3
+ * states. In such case it won't touch the variable
+ * of boot_option_idle_override.
+ */
+ idle_nomwait = 1;
+ return 0;
+ } else
return -1;
boot_option_idle_override = 1;
diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c
index f41d67f8f83..1eb2973a301 100644
--- a/arch/x86/mm/srat_32.c
+++ b/arch/x86/mm/srat_32.c
@@ -156,10 +156,9 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity)
num_memory_chunks++;
- printk(KERN_DEBUG "Memory range %08lx to %08lx (type %x)"
+ printk(KERN_DEBUG "Memory range %08lx to %08lx"
" in proximity domain %02x %s\n",
start_pfn, end_pfn,
- memory_affinity->memory_type,
pxm,
((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
"enabled and removable" : "enabled" ) );
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 40b0fcae4c7..4efbe598c81 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -21,7 +21,7 @@ obj-$(CONFIG_X86) += blacklist.o
#
# ACPI Core Subsystem (Interpreter)
#
-obj-y += osl.o utils.o \
+obj-y += osl.o utils.o reboot.o\
dispatcher/ events/ executer/ hardware/ \
namespace/ parser/ resources/ tables/ \
utilities/
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 61b6c5beb2d..e6caf5d42e0 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -380,6 +380,9 @@ static int __init bay_init(void)
if (acpi_disabled)
return -ENODEV;
+ if (acpi_disabled)
+ return -ENODEV;
+
/* look for dockable drive bays */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_bay, &bays, NULL);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a6dbcf4d9ef..afb34387d5f 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -612,7 +612,7 @@ static int __init acpi_bus_init_irq(void)
return 0;
}
-acpi_native_uint acpi_gbl_permanent_mmap;
+u8 acpi_gbl_permanent_mmap;
void __init acpi_early_init(void)
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index 610b1ee102b..949f7c75029 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -151,7 +151,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
******************************************************************************/
acpi_status
-acpi_ds_initialize_objects(acpi_native_uint table_index,
+acpi_ds_initialize_objects(u32 table_index,
struct acpi_namespace_node * start_node)
{
acpi_status status;
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 2509809a36c..4613b9ca579 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -377,7 +377,6 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
}
info->parameters = &this_walk_state->operands[0];
- info->parameter_type = ACPI_PARAM_ARGS;
status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
obj_desc->method.aml_start,
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index a818e0ddb99..6a81c4400ed 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -691,12 +691,6 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
status = acpi_ex_resolve_operands(op->common.aml_opcode,
ACPI_WALK_OPERANDS, walk_state);
-
- ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
- acpi_ps_get_opcode_name(op->common.aml_opcode),
- walk_state->num_operands,
- "after AcpiExResolveOperands");
-
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "(%s) bad operand(s) (%X)",
acpi_ps_get_opcode_name(op->common.aml_opcode),
@@ -785,10 +779,6 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}
- ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
- acpi_ps_get_opcode_name(op->common.aml_opcode),
- 1, "after AcpiExResolveOperands");
-
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
return_ACPI_STATUS(AE_NOT_EXIST);
@@ -848,7 +838,7 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
union acpi_operand_object **operand;
struct acpi_namespace_node *node;
union acpi_parse_object *next_op;
- acpi_native_uint table_index;
+ u32 table_index;
struct acpi_table_header *table;
ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
@@ -882,10 +872,6 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}
- ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
- acpi_ps_get_opcode_name(op->common.aml_opcode),
- 1, "after AcpiExResolveOperands");
-
operand = &walk_state->operands[0];
/* Find the ACPI table */
@@ -1091,10 +1077,8 @@ acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}
- ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
- acpi_ps_get_opcode_name(op->common.aml_opcode),
- 1, "after AcpiExResolveOperands");
-
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS,
+ acpi_ps_get_opcode_name(op->common.aml_opcode), 1);
/*
* Get the bank_value operand and save it
* (at Top of stack)
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index b246b9657ea..b5072fa9c92 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -408,14 +408,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
[walk_state->
num_operands - 1]),
walk_state);
- if (ACPI_SUCCESS(status)) {
- ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS,
- ACPI_IMODE_EXECUTE,
- acpi_ps_get_opcode_name
- (walk_state->opcode),
- walk_state->num_operands,
- "after ExResolveOperands");
- }
}
if (ACPI_SUCCESS(status)) {
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 1386ced332e..b00d4af791a 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -70,7 +70,7 @@ acpi_status
acpi_ds_result_pop(union acpi_operand_object **object,
struct acpi_walk_state *walk_state)
{
- acpi_native_uint index;
+ u32 index;
union acpi_generic_state *state;
acpi_status status;
@@ -122,7 +122,7 @@ acpi_ds_result_pop(union acpi_operand_object **object,
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
acpi_ut_get_object_type_name(*object),
- (u32) index, walk_state, walk_state->result_count));
+ index, walk_state, walk_state->result_count));
return (AE_OK);
}
@@ -146,7 +146,7 @@ acpi_ds_result_push(union acpi_operand_object * object,
{
union acpi_generic_state *state;
acpi_status status;
- acpi_native_uint index;
+ u32 index;
ACPI_FUNCTION_NAME(ds_result_push);
@@ -400,7 +400,7 @@ void
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
struct acpi_walk_state *walk_state)
{
- acpi_native_int i;
+ s32 i;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
@@ -409,7 +409,7 @@ acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
return;
}
- for (i = (acpi_native_int) (pop_count - 1); i >= 0; i--) {
+ for (i = (s32) pop_count - 1; i >= 0; i--) {
if (walk_state->num_operands == 0) {
return;
}
@@ -615,14 +615,8 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
walk_state->pass_number = pass_number;
if (info) {
- if (info->parameter_type == ACPI_PARAM_GPE) {
- walk_state->gpe_event_info =
- ACPI_CAST_PTR(struct acpi_gpe_event_info,
- info->parameters);
- } else {
- walk_state->params = info->parameters;
- walk_state->caller_return_desc = &info->return_object;
- }
+ walk_state->params = info->parameters;
+ walk_state->caller_return_desc = &info->return_object;
}
status = acpi_ps_init_scope(&walk_state->parser_state, op);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index bb7c51f712b..1e872e79db3 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -920,6 +920,9 @@ static int __init dock_init(void)
if (acpi_disabled)
return 0;
+ if (acpi_disabled)
+ return 0;
+
/* look for a dock station */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock, &num, NULL);
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 5d30e5be1b1..c56c5c6ea77 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -188,7 +188,7 @@ acpi_status acpi_ev_install_xrupt_handlers(void)
static acpi_status acpi_ev_fixed_event_initialize(void)
{
- acpi_native_uint i;
+ u32 i;
acpi_status status;
/*
@@ -231,7 +231,7 @@ u32 acpi_ev_fixed_event_detect(void)
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
u32 fixed_status;
u32 fixed_enable;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_NAME(ev_fixed_event_detect);
@@ -260,7 +260,7 @@ u32 acpi_ev_fixed_event_detect(void)
/* Found an active (signalled) event */
acpi_os_fixed_event_count(i);
- int_status |= acpi_ev_fixed_event_dispatch((u32) i);
+ int_status |= acpi_ev_fixed_event_dispatch(i);
}
}
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 5354be44f87..c5e53aae86f 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -256,7 +256,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
return_ACPI_STATUS(status);
}
- /* Mark wake-disabled or HW disable, or both */
+ /* Clear the appropriate enabled flags for this GPE */
switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
case ACPI_GPE_TYPE_WAKE:
@@ -273,13 +273,23 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Disable the requested runtime GPE */
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
-
- /* fallthrough */
+ break;
default:
- acpi_hw_write_gpe_enable_reg(gpe_event_info);
+ break;
}
+ /*
+ * Even if we don't know the GPE type, make sure that we always
+ * disable it. low_disable_gpe will just clear the enable bit for this
+ * GPE and write it. It will not write out the current GPE enable mask,
+ * since this may inadvertently enable GPEs too early, if a rogue GPE has
+ * come in during ACPICA initialization - possibly as a result of AML or
+ * other code that has enabled the GPE.
+ */
+ status = acpi_hw_low_disable_gpe(gpe_event_info);
+ return_ACPI_STATUS(status);
+
return_ACPI_STATUS(AE_OK);
}
@@ -305,7 +315,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
{
union acpi_operand_object *obj_desc;
struct acpi_gpe_block_info *gpe_block;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_ENTRY();
@@ -379,8 +389,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
u32 status_reg;
u32 enable_reg;
acpi_cpu_flags flags;
- acpi_native_uint i;
- acpi_native_uint j;
+ u32 i;
+ u32 j;
ACPI_FUNCTION_NAME(ev_gpe_detect);
@@ -462,13 +472,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
*/
int_status |=
acpi_ev_gpe_dispatch(&gpe_block->
- event_info[(i *
- ACPI_GPE_REGISTER_WIDTH)
- +
- j],
- (u32) j +
- gpe_register_info->
- base_gpe_number);
+ event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
}
}
}
@@ -555,10 +559,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
*/
info->prefix_node =
local_gpe_event_info.dispatch.method_node;
- info->parameters =
- ACPI_CAST_PTR(union acpi_operand_object *,
- gpe_event_info);
- info->parameter_type = ACPI_PARAM_GPE;
info->flags = ACPI_IGNORE_RETURN_VALUE;
status = acpi_ns_evaluate(info);
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index e6c4d4c49e7..73c058e2f5c 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -189,8 +189,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block)
{
struct acpi_gpe_event_info *gpe_event_info;
- acpi_native_uint i;
- acpi_native_uint j;
+ u32 i;
+ u32 j;
ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);
@@ -203,7 +203,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
gpe_event_info =
&gpe_block->
- event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+ event_info[((acpi_size) i *
+ ACPI_GPE_REGISTER_WIDTH) + j];
if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_HANDLER) {
@@ -744,8 +745,8 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
struct acpi_gpe_event_info *gpe_event_info = NULL;
struct acpi_gpe_event_info *this_event;
struct acpi_gpe_register_info *this_register;
- acpi_native_uint i;
- acpi_native_uint j;
+ u32 i;
+ u32 j;
acpi_status status;
ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
@@ -983,8 +984,8 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
struct acpi_gpe_walk_info gpe_info;
u32 wake_gpe_count;
u32 gpe_enabled_count;
- acpi_native_uint i;
- acpi_native_uint j;
+ u32 i;
+ u32 j;
ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
@@ -1033,7 +1034,8 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_event_info =
&gpe_block->
- event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+ event_info[((acpi_size) i *
+ ACPI_GPE_REGISTER_WIDTH) + j];
if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_METHOD)
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 2113e58e222..1d5670be729 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -575,7 +575,7 @@ acpi_status acpi_ev_release_global_lock(void)
void acpi_ev_terminate(void)
{
- acpi_native_uint i;
+ u32 i;
acpi_status status;
ACPI_FUNCTION_TRACE(ev_terminate);
@@ -589,7 +589,7 @@ void acpi_ev_terminate(void)
/* Disable all fixed events */
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
- status = acpi_disable_event((u32) i, 0);
+ status = acpi_disable_event(i, 0);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO,
"Could not disable fixed event %d",
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 1628f593475..236fbd1ca43 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -81,7 +81,7 @@ acpi_ev_install_handler(acpi_handle obj_handle,
acpi_status acpi_ev_install_region_handlers(void)
{
acpi_status status;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(ev_install_region_handlers);
@@ -151,7 +151,7 @@ acpi_status acpi_ev_install_region_handlers(void)
acpi_status acpi_ev_initialize_op_regions(void)
{
acpi_status status;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(ev_initialize_op_regions);
@@ -219,7 +219,6 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
info->prefix_node = region_obj2->extra.method_REG;
info->pathname = NULL;
info->parameters = args;
- info->parameter_type = ACPI_PARAM_ARGS;
info->flags = ACPI_IGNORE_RETURN_VALUE;
/*
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 2e3d2c5e4f4..6b94b38df07 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -380,7 +380,7 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
acpi_status status;
struct acpica_device_id hid;
struct acpi_compatible_id_list *cid;
- acpi_native_uint i;
+ u32 i;
/*
* Get the _HID and check for a PCI Root Bridge
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 99a7502e6a8..73bfd6bf962 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -472,7 +472,6 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
}
ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
-#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
* FUNCTION: acpi_get_event_status
@@ -489,6 +488,7 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
{
acpi_status status = AE_OK;
+ u32 value;
ACPI_FUNCTION_TRACE(acpi_get_event_status);
@@ -506,7 +506,20 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- status_register_id, event_status);
+ enable_register_id, &value);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
+ *event_status = value;
+
+ status =
+ acpi_get_register(acpi_gbl_fixed_event_info[event].
+ status_register_id, &value);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(status);
+
+ if (value)
+ *event_status |= ACPI_EVENT_FLAG_SET;
return_ACPI_STATUS(status);
}
@@ -566,7 +579,6 @@ acpi_get_gpe_status(acpi_handle gpe_device,
}
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
-#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
*
* FUNCTION: acpi_install_gpe_block
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 39d74219058..2a32c843cb4 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -53,7 +53,7 @@ ACPI_MODULE_NAME("exconfig")
/* Local prototypes */
static acpi_status
-acpi_ex_add_table(acpi_native_uint table_index,
+acpi_ex_add_table(u32 table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle);
@@ -73,7 +73,7 @@ acpi_ex_add_table(acpi_native_uint table_index,
******************************************************************************/
static acpi_status
-acpi_ex_add_table(acpi_native_uint table_index,
+acpi_ex_add_table(u32 table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle)
{
@@ -96,7 +96,8 @@ acpi_ex_add_table(acpi_native_uint table_index,
/* Install the new table into the local data structures */
- obj_desc->reference.object = ACPI_CAST_PTR(void, table_index);
+ obj_desc->reference.object = ACPI_CAST_PTR(void,
+ (unsigned long)table_index);
/* Add the table to the namespace */
@@ -128,12 +129,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
{
acpi_status status;
union acpi_operand_object **operand = &walk_state->operands[0];
- acpi_native_uint table_index;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *start_node;
struct acpi_namespace_node *parameter_node = NULL;
union acpi_operand_object *ddb_handle;
struct acpi_table_header *table;
+ u32 table_index;
ACPI_FUNCTION_TRACE(ex_load_table_op);
@@ -280,7 +281,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
{
union acpi_operand_object *ddb_handle;
struct acpi_table_desc table_desc;
- acpi_native_uint table_index;
+ u32 table_index;
acpi_status status;
u32 length;
@@ -437,7 +438,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
{
acpi_status status = AE_OK;
union acpi_operand_object *table_desc = ddb_handle;
- acpi_native_uint table_index;
+ u32 table_index;
struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -454,9 +455,9 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the table index from the ddb_handle */
+ /* Get the table index from the ddb_handle (acpi_size for 64-bit case) */
- table_index = (acpi_native_uint) table_desc->reference.object;
+ table_index = (u32) (acpi_size) table_desc->reference.object;
/* Invoke table handler if present */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index fd954b4ed83..261d97516d9 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -288,11 +288,11 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
u16 base, u8 * string, u8 data_width)
{
acpi_integer digit;
- acpi_native_uint i;
- acpi_native_uint j;
- acpi_native_uint k = 0;
- acpi_native_uint hex_length;
- acpi_native_uint decimal_length;
+ u32 i;
+ u32 j;
+ u32 k = 0;
+ u32 hex_length;
+ u32 decimal_length;
u32 remainder;
u8 supress_zeros;
@@ -348,7 +348,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer,
/* hex_length: 2 ascii hex chars per data byte */
- hex_length = (acpi_native_uint) ACPI_MUL_2(data_width);
+ hex_length = ACPI_MUL_2(data_width);
for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) {
/* Get one hex digit, most significant digits first */
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 60e62c4f057..ad09696d506 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -45,8 +45,6 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
-#include <acpi/actables.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("excreate")
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 74f1b22601b..2be2e2bf95b 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -580,25 +580,22 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
case ACPI_TYPE_BUFFER:
- acpi_os_printf("Buffer len %X @ %p\n",
+ acpi_os_printf("Buffer length %.2X @ %p\n",
obj_desc->buffer.length,
obj_desc->buffer.pointer);
- length = obj_desc->buffer.length;
- if (length > 64) {
- length = 64;
- }
-
/* Debug only -- dump the buffer contents */
if (obj_desc->buffer.pointer) {
- acpi_os_printf("Buffer Contents: ");
-
- for (index = 0; index < length; index++) {
- acpi_os_printf(" %02x",
- obj_desc->buffer.pointer[index]);
+ length = obj_desc->buffer.length;
+ if (length > 128) {
+ length = 128;
}
- acpi_os_printf("\n");
+
+ acpi_os_printf
+ ("Buffer Contents: (displaying length 0x%.2X)\n",
+ length);
+ ACPI_DUMP_BUFFER(obj_desc->buffer.pointer, length);
}
break;
@@ -756,54 +753,42 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
*
* FUNCTION: acpi_ex_dump_operands
*
- * PARAMETERS: Operands - Operand list
- * interpreter_mode - Load or Exec
- * Ident - Identification
- * num_levels - # of stack entries to dump above line
- * Note - Output notation
- * module_name - Caller's module name
- * line_number - Caller's invocation line number
+ * PARAMETERS: Operands - A list of Operand objects
+ * opcode_name - AML opcode name
+ * num_operands - Operand count for this opcode
*
- * DESCRIPTION: Dump the object stack
+ * DESCRIPTION: Dump the operands associated with the opcode
*
******************************************************************************/
void
acpi_ex_dump_operands(union acpi_operand_object **operands,
- acpi_interpreter_mode interpreter_mode,
- char *ident,
- u32 num_levels,
- char *note, char *module_name, u32 line_number)
+ const char *opcode_name, u32 num_operands)
{
- acpi_native_uint i;
-
ACPI_FUNCTION_NAME(ex_dump_operands);
- if (!ident) {
- ident = "?";
- }
-
- if (!note) {
- note = "?";
+ if (!opcode_name) {
+ opcode_name = "UNKNOWN";
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "************* Operand Stack Contents (Opcode [%s], %d Operands)\n",
- ident, num_levels));
+ "**** Start operand dump for opcode [%s], %d operands\n",
+ opcode_name, num_operands));
- if (num_levels == 0) {
- num_levels = 1;
+ if (num_operands == 0) {
+ num_operands = 1;
}
- /* Dump the operand stack starting at the top */
+ /* Dump the individual operands */
- for (i = 0; num_levels > 0; i--, num_levels--) {
- acpi_ex_dump_operand(operands[i], 0);
+ while (num_operands) {
+ acpi_ex_dump_operand(*operands, 0);
+ operands++;
+ num_operands--;
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "************* Operand Stack dump from %s(%d), %s\n",
- module_name, line_number, note));
+ "**** End operand dump for [%s]\n", opcode_name));
return;
}
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index e336b5dc7a5..9ff9d1f4615 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -153,14 +153,15 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
/*
* Slack mode only: We will go ahead and allow access to this
* field if it is within the region length rounded up to the next
- * access width boundary.
+ * access width boundary. acpi_size cast for 64-bit compile.
*/
if (ACPI_ROUND_UP(rgn_desc->region.length,
obj_desc->common_field.
access_byte_width) >=
- (obj_desc->common_field.base_byte_offset +
- (acpi_native_uint) obj_desc->common_field.
- access_byte_width + field_datum_byte_offset)) {
+ ((acpi_size) obj_desc->common_field.
+ base_byte_offset +
+ obj_desc->common_field.access_byte_width +
+ field_datum_byte_offset)) {
return_ACPI_STATUS(AE_OK);
}
}
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index cc956a5b526..731414a581a 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -329,8 +329,8 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
/* Result of two Strings is a String */
- return_desc = acpi_ut_create_string_object((acpi_size)
- (operand0->string.
+ return_desc = acpi_ut_create_string_object(((acpi_size)
+ operand0->string.
length +
local_operand1->
string.length));
@@ -352,8 +352,8 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
/* Result of two Buffers is a Buffer */
- return_desc = acpi_ut_create_buffer_object((acpi_size)
- (operand0->buffer.
+ return_desc = acpi_ut_create_buffer_object(((acpi_size)
+ operand0->buffer.
length +
local_operand1->
buffer.length));
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 3a2f8cd4c62..5d438c32989 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -503,11 +503,11 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
*/
second_desc = obj_desc->common.next_object;
second_desc->extra.aml_start =
- ((union acpi_parse_object *)(info->data_register_node))->
- named.data;
+ ACPI_CAST_PTR(union acpi_parse_object,
+ info->data_register_node)->named.data;
second_desc->extra.aml_length =
- ((union acpi_parse_object *)(info->data_register_node))->
- named.length;
+ ACPI_CAST_PTR(union acpi_parse_object,
+ info->data_register_node)->named.length;
break;
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 7cd8bb54fa0..7a41c409ae4 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -156,7 +156,7 @@ acpi_ex_system_memory_space_handler(u32 function,
/* Create a new mapping starting at the address given */
mem_info->mapped_logical_address =
- acpi_os_map_memory((acpi_native_uint) address, window_size);
+ acpi_os_map_memory((acpi_physical_address) address, window_size);
if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 73e29e566a7..54085f16ec2 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -698,5 +698,9 @@ acpi_ex_resolve_operands(u16 opcode,
}
}
+ ACPI_DUMP_OPERANDS(walk_state->operands,
+ acpi_ps_get_opcode_name(opcode),
+ walk_state->num_operands);
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 76c875bc315..38b55e35249 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -343,12 +343,6 @@ acpi_ex_store(union acpi_operand_object *source_desc,
acpi_ut_get_object_type_name(dest_desc),
dest_desc));
- ACPI_DUMP_STACK_ENTRY(source_desc);
- ACPI_DUMP_STACK_ENTRY(dest_desc);
- ACPI_DUMP_OPERANDS(&dest_desc, ACPI_IMODE_EXECUTE, "ExStore",
- 2,
- "Target is not a Reference or Constant object");
-
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 6cf10cbc1ee..55c17afbe66 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -148,7 +148,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
int result = 0;
struct seq_file *m = file->private_data;
struct acpi_device *device = m->private;
- char state_string[12] = { '\0' };
+ char state_string[3] = { '\0' };
if (count > sizeof(state_string) - 1)
return -EINVAL;
@@ -157,6 +157,12 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
return -EFAULT;
state_string[count] = '\0';
+ if ((state_string[0] < '0') || (state_string[0] > '3'))
+ return -EINVAL;
+ if (state_string[1] == '\n')
+ state_string[1] = '\0';
+ if (state_string[1] != '\0')
+ return -EINVAL;
result = acpi_bus_set_power(device->handle,
simple_strtoul(state_string, NULL, 0));
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 9b227d4dc9c..6d18ca34b6a 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -336,6 +336,9 @@ static int __init acpi_rtc_init(void)
if (acpi_disabled)
return 0;
+ if (acpi_disabled)
+ return 0;
+
if (dev) {
rtc_wake_setup();
rtc_info.wake_on = rtc_wake_on;
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 14bc4f456ae..0b80db9d919 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -55,6 +55,54 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/******************************************************************************
*
+ * FUNCTION: acpi_hw_low_disable_gpe
+ *
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable a single GPE in the enable register.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+{
+ struct acpi_gpe_register_info *gpe_register_info;
+ acpi_status status;
+ u32 enable_mask;
+
+ /* Get the info block for the entire GPE register */
+
+ gpe_register_info = gpe_event_info->register_info;
+ if (!gpe_register_info) {
+ return (AE_NOT_EXIST);
+ }
+
+ /* Get current value of the enable register that contains this GPE */
+
+ status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask,
+ &gpe_register_info->enable_address);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Clear just the bit that corresponds to this GPE */
+
+ ACPI_CLEAR_BIT(enable_mask,
+ ((u32) 1 <<
+ (gpe_event_info->gpe_number -
+ gpe_register_info->base_gpe_number)));
+
+ /* Write the updated enable mask */
+
+ status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask,
+ &gpe_register_info->enable_address);
+
+ return (status);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_hw_write_gpe_enable_reg
*
* PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
@@ -68,7 +116,7 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
******************************************************************************/
acpi_status
-acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
+acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
{
struct acpi_gpe_register_info *gpe_register_info;
acpi_status status;
@@ -138,7 +186,6 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
*
******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
acpi_event_status * event_status)
@@ -198,7 +245,6 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
unlock_and_exit:
return (status);
}
-#endif /* ACPI_FUTURE_USAGE */
/******************************************************************************
*
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index 5445751b8a3..0ab22004728 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -73,7 +73,7 @@ acpi_ns_dump_one_device(acpi_handle obj_handle,
void acpi_ns_print_pathname(u32 num_segments, char *pathname)
{
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_NAME(ns_print_pathname);
@@ -515,12 +515,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
if (obj_type > ACPI_TYPE_LOCAL_MAX) {
acpi_os_printf
- ("(Ptr to ACPI Object type %X [UNKNOWN])\n",
+ ("(Pointer to ACPI Object type %.2X [UNKNOWN])\n",
obj_type);
bytes_to_dump = 32;
} else {
acpi_os_printf
- ("(Ptr to ACPI Object type %X [%s])\n",
+ ("(Pointer to ACPI Object type %.2X [%s])\n",
obj_type, acpi_ut_get_type_name(obj_type));
bytes_to_dump =
sizeof(union acpi_operand_object);
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 14bdfa92bea..d369164e00b 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -138,6 +138,41 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
return_ACPI_STATUS(AE_NULL_OBJECT);
}
+ /*
+ * Calculate the number of arguments being passed to the method
+ */
+
+ info->param_count = 0;
+ if (info->parameters) {
+ while (info->parameters[info->param_count])
+ info->param_count++;
+ }
+
+ /* Error if too few arguments were passed in */
+
+ if (info->param_count < info->obj_desc->method.param_count) {
+ ACPI_ERROR((AE_INFO,
+ "Insufficient arguments - "
+ "method [%4.4s] needs %d, found %d",
+ acpi_ut_get_node_name(info->resolved_node),
+ info->obj_desc->method.param_count,
+ info->param_count));
+ return_ACPI_STATUS(AE_MISSING_ARGUMENTS);
+ }
+
+ /* Just a warning if too many arguments */
+
+ else if (info->param_count >
+ info->obj_desc->method.param_count) {
+ ACPI_WARNING((AE_INFO,
+ "Excess arguments - "
+ "method [%4.4s] needs %d, found %d",
+ acpi_ut_get_node_name(info->
+ resolved_node),
+ info->obj_desc->method.param_count,
+ info->param_count));
+ }
+
ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:",
ACPI_LV_INFO, _COMPONENT);
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index 6d6d930c8e1..e4c57510d79 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -542,7 +542,6 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
info->prefix_node = device_node;
info->pathname = METHOD_NAME__INI;
info->parameters = NULL;
- info->parameter_type = ACPI_PARAM_ARGS;
info->flags = ACPI_IGNORE_RETURN_VALUE;
/*
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index 2c92f6cf5ce..a4a412b7c02 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -71,8 +71,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
******************************************************************************/
acpi_status
-acpi_ns_load_table(acpi_native_uint table_index,
- struct acpi_namespace_node *node)
+acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node)
{
acpi_status status;
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index 46a79b0103b..a82271a9dbb 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -63,13 +63,13 @@ ACPI_MODULE_NAME("nsparse")
*
******************************************************************************/
acpi_status
-acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index,
- struct acpi_namespace_node * start_node)
+acpi_ns_one_complete_parse(u32 pass_number,
+ u32 table_index,
+ struct acpi_namespace_node *start_node)
{
union acpi_parse_object *parse_root;
acpi_status status;
- acpi_native_uint aml_length;
+ u32 aml_length;
u8 *aml_start;
struct acpi_walk_state *walk_state;
struct acpi_table_header *table;
@@ -112,8 +112,8 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number,
aml_start = (u8 *) table + sizeof(struct acpi_table_header);
aml_length = table->length - sizeof(struct acpi_table_header);
status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
- aml_start, (u32) aml_length,
- NULL, (u8) pass_number);
+ aml_start, aml_length, NULL,
+ (u8) pass_number);
}
if (ACPI_FAILURE(status)) {
@@ -158,8 +158,7 @@ acpi_ns_one_complete_parse(acpi_native_uint pass_number,
******************************************************************************/
acpi_status
-acpi_ns_parse_table(acpi_native_uint table_index,
- struct acpi_namespace_node *start_node)
+acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
{
acpi_status status;
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 64c039843ed..b0817e1127b 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -73,9 +73,9 @@ acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
******************************************************************************/
void
-acpi_ns_report_error(char *module_name,
+acpi_ns_report_error(const char *module_name,
u32 line_number,
- char *internal_name, acpi_status lookup_status)
+ const char *internal_name, acpi_status lookup_status)
{
acpi_status status;
u32 bad_name;
@@ -130,11 +130,11 @@ acpi_ns_report_error(char *module_name,
******************************************************************************/
void
-acpi_ns_report_method_error(char *module_name,
+acpi_ns_report_method_error(const char *module_name,
u32 line_number,
- char *message,
+ const char *message,
struct acpi_namespace_node *prefix_node,
- char *path, acpi_status method_status)
+ const char *path, acpi_status method_status)
{
acpi_status status;
struct acpi_namespace_node *node = prefix_node;
@@ -167,7 +167,8 @@ acpi_ns_report_method_error(char *module_name,
******************************************************************************/
void
-acpi_ns_print_node_pathname(struct acpi_namespace_node *node, char *message)
+acpi_ns_print_node_pathname(struct acpi_namespace_node *node,
+ const char *message)
{
struct acpi_buffer buffer;
acpi_status status;
@@ -296,7 +297,7 @@ u32 acpi_ns_local(acpi_object_type type)
void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info)
{
- char *next_external_char;
+ const char *next_external_char;
u32 i;
ACPI_FUNCTION_ENTRY();
@@ -363,9 +364,9 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
{
u32 num_segments = info->num_segments;
char *internal_name = info->internal_name;
- char *external_name = info->next_external_char;
+ const char *external_name = info->next_external_char;
char *result = NULL;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(ns_build_internal_name);
@@ -400,12 +401,11 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
result = &internal_name[i];
} else if (num_segments == 2) {
internal_name[i] = AML_DUAL_NAME_PREFIX;
- result = &internal_name[(acpi_native_uint) (i + 1)];
+ result = &internal_name[(acpi_size) i + 1];
} else {
internal_name[i] = AML_MULTI_NAME_PREFIX_OP;
- internal_name[(acpi_native_uint) (i + 1)] =
- (char)num_segments;
- result = &internal_name[(acpi_native_uint) (i + 2)];
+ internal_name[(acpi_size) i + 1] = (char)num_segments;
+ result = &internal_name[(acpi_size) i + 2];
}
}
@@ -472,7 +472,8 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
*
*******************************************************************************/
-acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name)
+acpi_status
+acpi_ns_internalize_name(const char *external_name, char **converted_name)
{
char *internal_name;
struct acpi_namestring_info info;
@@ -528,15 +529,15 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name)
acpi_status
acpi_ns_externalize_name(u32 internal_name_length,
- char *internal_name,
+ const char *internal_name,
u32 * converted_name_length, char **converted_name)
{
- acpi_native_uint names_index = 0;
- acpi_native_uint num_segments = 0;
- acpi_native_uint required_length;
- acpi_native_uint prefix_length = 0;
- acpi_native_uint i = 0;
- acpi_native_uint j = 0;
+ u32 names_index = 0;
+ u32 num_segments = 0;
+ u32 required_length;
+ u32 prefix_length = 0;
+ u32 i = 0;
+ u32 j = 0;
ACPI_FUNCTION_TRACE(ns_externalize_name);
@@ -582,9 +583,8 @@ acpi_ns_externalize_name(u32 internal_name_length,
/* <count> 4-byte names */
names_index = prefix_length + 2;
- num_segments = (acpi_native_uint) (u8)
- internal_name[(acpi_native_uint)
- (prefix_length + 1)];
+ num_segments = (u8)
+ internal_name[(acpi_size) prefix_length + 1];
break;
case AML_DUAL_NAME_PREFIX:
@@ -823,7 +823,7 @@ u32 acpi_ns_opens_scope(acpi_object_type type)
acpi_status
acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
- char *pathname,
+ const char *pathname,
u32 flags, struct acpi_namespace_node **return_node)
{
union acpi_generic_state scope_info;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index a8d549187c8..38be5865d95 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -182,7 +182,6 @@ acpi_evaluate_object(acpi_handle handle,
}
info->pathname = pathname;
- info->parameter_type = ACPI_PARAM_ARGS;
/* Convert and validate the device handle */
@@ -442,7 +441,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
u32 flags;
struct acpica_device_id hid;
struct acpi_compatible_id_list *cid;
- acpi_native_uint i;
+ u32 i;
int found;
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 658e5f3abae..cb9864e39ba 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -120,10 +120,10 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
struct acpi_srat_mem_affinity *p =
(struct acpi_srat_mem_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n",
+ "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s\n",
(unsigned long)p->base_address,
(unsigned long)p->length,
- p->memory_type, p->proximity_domain,
+ p->proximity_domain,
(p->flags & ACPI_SRAT_MEM_ENABLED)?
"enabled" : "disabled",
(p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index e9446377884..d830b29b85b 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -76,7 +76,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
{
u8 *aml = parser_state->aml;
u32 package_length = 0;
- acpi_native_uint byte_count;
+ u32 byte_count;
u8 byte_zero_mask = 0x3F; /* Default [0:5] */
ACPI_FUNCTION_TRACE(ps_get_next_package_length);
@@ -86,7 +86,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
* used to encode the package length, either 0,1,2, or 3
*/
byte_count = (aml[0] >> 6);
- parser_state->aml += (byte_count + 1);
+ parser_state->aml += ((acpi_size) byte_count + 1);
/* Get bytes 3, 2, 1 as needed */
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 52581454c47..270469aae84 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -333,9 +333,9 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
static void
acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action)
{
- acpi_native_uint i;
+ u32 i;
- if ((info->parameter_type == ACPI_PARAM_ARGS) && (info->parameters)) {
+ if (info->parameters) {
/* Update reference count for each parameter */
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 89022a74fae..11acaee14d6 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -162,7 +162,7 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt)
!strcmp(prt->source, quirk->source) &&
strlen(prt->source) >= strlen(quirk->actual_source)) {
printk(KERN_WARNING PREFIX "firmware reports "
- "%04x:%02x:%02x[%c] connected to %s; "
+ "%04x:%02x:%02x PCI INT %c connected to %s; "
"changing to %s\n",
entry->id.segment, entry->id.bus,
entry->id.device, 'A' + entry->pin,
@@ -429,7 +429,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,
{
struct pci_dev *bridge = dev;
int irq = -1;
- u8 bridge_pin = 0;
+ u8 bridge_pin = 0, orig_pin = pin;
if (!dev)
@@ -463,8 +463,8 @@ acpi_pci_irq_derive(struct pci_dev *dev,
}
if (irq < 0) {
- printk(KERN_WARNING PREFIX "Unable to derive IRQ for device %s\n",
- pci_name(dev));
+ dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
+ 'A' + orig_pin);
return -1;
}
@@ -487,6 +487,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
int triggering = ACPI_LEVEL_SENSITIVE;
int polarity = ACPI_ACTIVE_LOW;
char *link = NULL;
+ char link_desc[16];
int rc;
@@ -503,7 +504,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
pin--;
if (!dev->bus) {
- printk(KERN_ERR PREFIX "Invalid (NULL) 'bus' field\n");
+ dev_err(&dev->dev, "invalid (NULL) 'bus' field\n");
return -ENODEV;
}
@@ -538,8 +539,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
* driver reported one, then use it. Exit in any case.
*/
if (irq < 0) {
- printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
- pci_name(dev), ('A' + pin));
+ dev_warn(&dev->dev, "PCI INT %c: no GSI", 'A' + pin);
/* Interrupt Line values above 0xF are forbidden */
if (dev->irq > 0 && (dev->irq <= 0xF)) {
printk(" - using IRQ %d\n", dev->irq);
@@ -554,21 +554,21 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
rc = acpi_register_gsi(irq, triggering, polarity);
if (rc < 0) {
- printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed "
- "to register GSI\n", pci_name(dev), ('A' + pin));
+ dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
+ 'A' + pin);
return rc;
}
dev->irq = rc;
- printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
- pci_name(dev), 'A' + pin);
-
if (link)
- printk("Link [%s] -> ", link);
+ snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
+ else
+ link_desc[0] = '\0';
- printk("GSI %u (%s, %s) -> IRQ %d\n", irq,
- (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
- (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
+ dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
+ 'A' + pin, link_desc, irq,
+ (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
+ (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
return 0;
}
@@ -616,10 +616,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
* (e.g. PCI_UNDEFINED_IRQ).
*/
- printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n",
- pci_name(dev));
-
+ dev_info(&dev->dev, "PCI INT %c disabled\n", 'A' + pin);
acpi_unregister_gsi(gsi);
-
- return;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 9dd0fa93b9e..ec0f2d581ec 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -118,8 +118,31 @@ static const struct file_operations acpi_processor_info_fops = {
.release = single_release,
};
-struct acpi_processor *processors[NR_CPUS];
+DEFINE_PER_CPU(struct acpi_processor *, processors);
struct acpi_processor_errata errata __read_mostly;
+static int set_no_mwait(const struct dmi_system_id *id)
+{
+ printk(KERN_NOTICE PREFIX "%s detected - "
+ "disable mwait for CPU C-stetes\n", id->ident);
+ idle_nomwait = 1;
+ return 0;
+}
+
+static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
+ {
+ set_no_mwait, "IFL91 board", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
+ DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
+ DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
+ {
+ set_no_mwait, "Extensa 5220", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+ DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
+ {},
+};
/* --------------------------------------------------------------------------
Errata Handling
@@ -265,7 +288,20 @@ static int acpi_processor_set_pdc(struct acpi_processor *pr)
if (!pdc_in)
return status;
+ if (idle_nomwait) {
+ /*
+ * If mwait is disabled for CPU C-states, the C2C3_FFH access
+ * mode will be disabled in the parameter of _PDC object.
+ * Of course C1_FFH access mode will also be disabled.
+ */
+ union acpi_object *obj;
+ u32 *buffer = NULL;
+ obj = pdc_in->pointer;
+ buffer = (u32 *)(obj->buffer.pointer);
+ buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
+
+ }
status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
if (ACPI_FAILURE(status))
@@ -614,14 +650,14 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
return 0;
}
-static void *processor_device_array[NR_CPUS];
+static DEFINE_PER_CPU(void *, processor_device_array);
static int __cpuinit acpi_processor_start(struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_processor *pr;
-
+ struct sys_device *sysdev;
pr = acpi_driver_data(device);
@@ -638,20 +674,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
* ACPI id of processors can be reported wrongly by the BIOS.
* Don't trust it blindly
*/
- if (processor_device_array[pr->id] != NULL &&
- processor_device_array[pr->id] != device) {
+ if (per_cpu(processor_device_array, pr->id) != NULL &&
+ per_cpu(processor_device_array, pr->id) != device) {
printk(KERN_WARNING "BIOS reported wrong ACPI id "
"for the processor\n");
return -ENODEV;
}
- processor_device_array[pr->id] = device;
+ per_cpu(processor_device_array, pr->id) = device;
- processors[pr->id] = pr;
+ per_cpu(processors, pr->id) = pr;
result = acpi_processor_add_fs(device);
if (result)
goto end;
+ sysdev = get_cpu_sysdev(pr->id);
+ if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev"))
+ return -EFAULT;
+
status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify, pr);
@@ -749,7 +789,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
- struct acpi_processor *pr = processors[cpu];
+ struct acpi_processor *pr = per_cpu(processors, cpu);
if (action == CPU_ONLINE && pr) {
acpi_processor_ppc_has_changed(pr);
@@ -810,6 +850,8 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify);
+ sysfs_remove_link(&device->dev.kobj, "sysdev");
+
acpi_processor_remove_fs(device);
if (pr->cdev) {
@@ -819,8 +861,8 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
pr->cdev = NULL;
}
- processors[pr->id] = NULL;
- processor_device_array[pr->id] = NULL;
+ per_cpu(processors, pr->id) = NULL;
+ per_cpu(processor_device_array, pr->id) = NULL;
kfree(pr);
return 0;
@@ -1014,9 +1056,9 @@ static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
static int acpi_processor_handle_eject(struct acpi_processor *pr)
{
- if (cpu_online(pr->id)) {
- return (-EINVAL);
- }
+ if (cpu_online(pr->id))
+ cpu_down(pr->id);
+
arch_unregister_cpu(pr->id);
acpi_unmap_lsapic(pr->id);
return (0);
@@ -1068,8 +1110,6 @@ static int __init acpi_processor_init(void)
{
int result = 0;
-
- memset(&processors, 0, sizeof(processors));
memset(&errata, 0, sizeof(errata));
#ifdef CONFIG_SMP
@@ -1083,6 +1123,11 @@ static int __init acpi_processor_init(void)
return -ENOMEM;
acpi_processor_dir->owner = THIS_MODULE;
+ /*
+ * Check whether the system is DMI table. If yes, OSPM
+ * should not use mwait for CPU-states.
+ */
+ dmi_check_system(processor_idle_dmi_table);
result = cpuidle_register_driver(&acpi_idle_driver);
if (result < 0)
goto out_proc;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 4976e5db2b3..d592dbb1d12 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -41,6 +41,7 @@
#include <linux/pm_qos_params.h>
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
+#include <linux/cpuidle.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
@@ -57,6 +58,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
+#include <asm/processor.h>
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
@@ -401,7 +403,7 @@ static void acpi_processor_idle(void)
*/
local_irq_disable();
- pr = processors[smp_processor_id()];
+ pr = __get_cpu_var(processors);
if (!pr) {
local_irq_enable();
return;
@@ -955,6 +957,21 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
} else {
continue;
}
+ if (cx.type == ACPI_STATE_C1 &&
+ (idle_halt || idle_nomwait)) {
+ /*
+ * In most cases the C1 space_id obtained from
+ * _CST object is FIXED_HARDWARE access mode.
+ * But when the option of idle=halt is added,
+ * the entry_method type should be changed from
+ * CSTATE_FFH to CSTATE_HALT.
+ * When the option of idle=nomwait is added,
+ * the C1 entry_method type should be
+ * CSTATE_HALT.
+ */
+ cx.entry_method = ACPI_CSTATE_HALT;
+ snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
+ }
} else {
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
cx.address);
@@ -1431,7 +1448,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct acpi_processor *pr;
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
- pr = processors[smp_processor_id()];
+ pr = __get_cpu_var(processors);
if (unlikely(!pr))
return 0;
@@ -1471,7 +1488,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
u32 t1, t2;
int sleep_ticks = 0;
- pr = processors[smp_processor_id()];
+ pr = __get_cpu_var(processors);
if (unlikely(!pr))
return 0;
@@ -1549,7 +1566,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
u32 t1, t2;
int sleep_ticks = 0;
- pr = processors[smp_processor_id()];
+ pr = __get_cpu_var(processors);
if (unlikely(!pr))
return 0;
@@ -1780,6 +1797,15 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
return 0;
if (!first_run) {
+ if (idle_halt) {
+ /*
+ * When the boot option of "idle=halt" is added, halt
+ * is used for CPU IDLE.
+ * In such case C2/C3 is meaningless. So the max_cstate
+ * is set to one.
+ */
+ max_cstate = 1;
+ }
dmi_check_system(processor_power_dmi_table);
max_cstate = acpi_processor_cstate_check(max_cstate);
if (max_cstate < ACPI_C_STATES_MAX)
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index d80b2d1441a..b4749969c6b 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -89,7 +89,7 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
if (event != CPUFREQ_INCOMPATIBLE)
goto out;
- pr = processors[policy->cpu];
+ pr = per_cpu(processors, policy->cpu);
if (!pr || !pr->performance)
goto out;
@@ -572,7 +572,7 @@ int acpi_processor_preregister_performance(
/* Call _PSD for all CPUs */
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr) {
/* Look only at processors in ACPI namespace */
continue;
@@ -603,7 +603,7 @@ int acpi_processor_preregister_performance(
* domain info.
*/
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr)
continue;
@@ -624,7 +624,7 @@ int acpi_processor_preregister_performance(
cpus_clear(covered_cpus);
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr)
continue;
@@ -651,7 +651,7 @@ int acpi_processor_preregister_performance(
if (i == j)
continue;
- match_pr = processors[j];
+ match_pr = per_cpu(processors, j);
if (!match_pr)
continue;
@@ -680,7 +680,7 @@ int acpi_processor_preregister_performance(
if (i == j)
continue;
- match_pr = processors[j];
+ match_pr = per_cpu(processors, j);
if (!match_pr)
continue;
@@ -697,7 +697,7 @@ int acpi_processor_preregister_performance(
err_ret:
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr || !pr->performance)
continue;
@@ -728,7 +728,7 @@ acpi_processor_register_performance(struct acpi_processor_performance
mutex_lock(&performance_mutex);
- pr = processors[cpu];
+ pr = per_cpu(processors, cpu);
if (!pr) {
mutex_unlock(&performance_mutex);
return -ENODEV;
@@ -766,7 +766,7 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
mutex_lock(&performance_mutex);
- pr = processors[cpu];
+ pr = per_cpu(processors, cpu);
if (!pr) {
mutex_unlock(&performance_mutex);
return;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index bb06738860c..0622ace0522 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -71,7 +71,7 @@ static int acpi_processor_update_tsd_coord(void)
* coordination between all CPUs.
*/
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr)
continue;
@@ -93,7 +93,7 @@ static int acpi_processor_update_tsd_coord(void)
cpus_clear(covered_cpus);
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr)
continue;
@@ -119,7 +119,7 @@ static int acpi_processor_update_tsd_coord(void)
if (i == j)
continue;
- match_pr = processors[j];
+ match_pr = per_cpu(processors, j);
if (!match_pr)
continue;
@@ -152,7 +152,7 @@ static int acpi_processor_update_tsd_coord(void)
if (i == j)
continue;
- match_pr = processors[j];
+ match_pr = per_cpu(processors, j);
if (!match_pr)
continue;
@@ -172,7 +172,7 @@ static int acpi_processor_update_tsd_coord(void)
err_ret:
for_each_possible_cpu(i) {
- pr = processors[i];
+ pr = per_cpu(processors, i);
if (!pr)
continue;
@@ -214,7 +214,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data)
struct acpi_processor_throttling *p_throttling;
cpu = p_tstate->cpu;
- pr = processors[cpu];
+ pr = per_cpu(processors, cpu);
if (!pr) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid pr pointer\n"));
return 0;
@@ -1035,7 +1035,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
* cpus.
*/
for_each_cpu_mask(i, online_throttling_cpus) {
- match_pr = processors[i];
+ match_pr = per_cpu(processors, i);
/*
* If the pointer is invalid, we will report the
* error message and continue.
@@ -1232,7 +1232,10 @@ static ssize_t acpi_processor_write_throttling(struct file *file,
int result = 0;
struct seq_file *m = file->private_data;
struct acpi_processor *pr = m->private;
- char state_string[12] = { '\0' };
+ char state_string[5] = "";
+ char *charp = NULL;
+ size_t state_val = 0;
+ char tmpbuf[5] = "";
if (!pr || (count > sizeof(state_string) - 1))
return -EINVAL;
@@ -1241,10 +1244,23 @@ static ssize_t acpi_processor_write_throttling(struct file *file,
return -EFAULT;
state_string[count] = '\0';
+ if ((count > 0) && (state_string[count-1] == '\n'))
+ state_string[count-1] = '\0';
- result = acpi_processor_set_throttling(pr,
- simple_strtoul(state_string,
- NULL, 0));
+ charp = state_string;
+ if ((state_string[0] == 't') || (state_string[0] == 'T'))
+ charp++;
+
+ state_val = simple_strtoul(charp, NULL, 0);
+ if (state_val >= pr->throttling.state_count)
+ return -EINVAL;
+
+ snprintf(tmpbuf, 5, "%zu", state_val);
+
+ if (strcmp(tmpbuf, charp) != 0)
+ return -EINVAL;
+
+ result = acpi_processor_set_throttling(pr, state_val);
if (result)
return result;
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c
new file mode 100644
index 00000000000..a6b662c00b6
--- /dev/null
+++ b/drivers/acpi/reboot.c
@@ -0,0 +1,50 @@
+
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/reboot.h>
+
+void acpi_reboot(void)
+{
+ struct acpi_generic_address *rr;
+ struct pci_bus *bus0;
+ u8 reset_value;
+ unsigned int devfn;
+
+ if (acpi_disabled)
+ return;
+
+ rr = &acpi_gbl_FADT.reset_register;
+
+ /* Is the reset register supported? */
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
+ rr->bit_width != 8 || rr->bit_offset != 0)
+ return;
+
+ reset_value = acpi_gbl_FADT.reset_value;
+
+ /* The reset register can only exist in I/O, Memory or PCI config space
+ * on a device on bus 0. */
+ switch (rr->space_id) {
+ case ACPI_ADR_SPACE_PCI_CONFIG:
+ /* The reset register can only live on bus 0. */
+ bus0 = pci_find_bus(0, 0);
+ if (!bus0)
+ return;
+ /* Form PCI device/function pair. */
+ devfn = PCI_DEVFN((rr->address >> 32) & 0xffff,
+ (rr->address >> 16) & 0xffff);
+ printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.");
+ /* Write the value that resets us. */
+ pci_bus_write_config_byte(bus0, devfn,
+ (rr->address & 0xffff), reset_value);
+ break;
+
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n");
+ acpi_hw_low_level_write(8, reset_value, rr);
+ break;
+ }
+ /* Wait ten seconds */
+ acpi_os_stall(10000000);
+}
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index 8a112d11d49..f61ebc679e6 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -73,7 +73,7 @@ acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length);
static u8 acpi_rs_count_set_bits(u16 bit_field)
{
- acpi_native_uint bits_set;
+ u8 bits_set;
ACPI_FUNCTION_ENTRY();
@@ -84,7 +84,7 @@ static u8 acpi_rs_count_set_bits(u16 bit_field)
bit_field &= (u16) (bit_field - 1);
}
- return ((u8) bits_set);
+ return bits_set;
}
/*******************************************************************************
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index faddaee1bc0..7804a8c40e7 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -181,9 +181,9 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
}
/*
- * Loop through the ACPI_INTERNAL_OBJECTS - Each object
- * should be a package that in turn contains an
- * acpi_integer Address, a u8 Pin, a Name and a u8 source_index.
+ * Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a
+ * package that in turn contains an acpi_integer Address, a u8 Pin,
+ * a Name, and a u8 source_index.
*/
top_object_list = package_object->package.elements;
number_of_elements = package_object->package.count;
@@ -240,9 +240,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 1) First subobject: Dereference the PRT.Address */
obj_desc = sub_object_list[0];
- if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
- user_prt->address = obj_desc->integer.value;
- } else {
+ if (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%X].Address) Need Integer, found %s",
index,
@@ -250,12 +248,12 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
return_ACPI_STATUS(AE_BAD_DATA);
}
+ user_prt->address = obj_desc->integer.value;
+
/* 2) Second subobject: Dereference the PRT.Pin */
obj_desc = sub_object_list[1];
- if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
- user_prt->pin = (u32) obj_desc->integer.value;
- } else {
+ if (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%X].Pin) Need Integer, found %s",
index,
@@ -284,6 +282,25 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
}
}
+ user_prt->pin = (u32) obj_desc->integer.value;
+
+ /*
+ * If the BIOS has erroneously reversed the _PRT source_name (index 2)
+ * and the source_index (index 3), fix it. _PRT is important enough to
+ * workaround this BIOS error. This also provides compatibility with
+ * other ACPI implementations.
+ */
+ obj_desc = sub_object_list[3];
+ if (!obj_desc
+ || (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) {
+ sub_object_list[3] = sub_object_list[2];
+ sub_object_list[2] = obj_desc;
+
+ ACPI_WARNING((AE_INFO,
+ "(PRT[%X].Source) SourceName and SourceIndex are reversed, fixed",
+ index));
+ }
+
/*
* 3) Third subobject: Dereference the PRT.source_name
* The name may be unresolved (slack mode), so allow a null object
@@ -364,9 +381,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
/* 4) Fourth subobject: Dereference the PRT.source_index */
obj_desc = sub_object_list[source_index_index];
- if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) {
- user_prt->source_index = (u32) obj_desc->integer.value;
- } else {
+ if (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER) {
ACPI_ERROR((AE_INFO,
"(PRT[%X].SourceIndex) Need Integer, found %s",
index,
@@ -374,6 +389,8 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
return_ACPI_STATUS(AE_BAD_DATA);
}
+ user_prt->source_index = (u32) obj_desc->integer.value;
+
/* Point to the next union acpi_operand_object in the top level package */
top_object_list++;
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index de1ac3881b2..96a6c035325 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -82,7 +82,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource);
- if (((acpi_native_uint) resource) & 0x3) {
+ if (((acpi_size) resource) & 0x3) {
/* Each internal resource struct is expected to be 32-bit aligned */
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index befe2302f41..f7b3bcd59ba 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -62,7 +62,7 @@ ACPI_MODULE_NAME("rsutils")
******************************************************************************/
u8 acpi_rs_decode_bitmask(u16 mask, u8 * list)
{
- acpi_native_uint i;
+ u8 i;
u8 bit_count;
ACPI_FUNCTION_ENTRY();
@@ -71,7 +71,7 @@ u8 acpi_rs_decode_bitmask(u16 mask, u8 * list)
for (i = 0, bit_count = 0; mask; i++) {
if (mask & 0x0001) {
- list[bit_count] = (u8) i;
+ list[bit_count] = i;
bit_count++;
}
@@ -96,8 +96,8 @@ u8 acpi_rs_decode_bitmask(u16 mask, u8 * list)
u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
{
- acpi_native_uint i;
- acpi_native_uint mask;
+ u32 i;
+ u16 mask;
ACPI_FUNCTION_ENTRY();
@@ -107,7 +107,7 @@ u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
mask |= (0x1 << list[i]);
}
- return ((u16) mask);
+ return mask;
}
/*******************************************************************************
@@ -130,7 +130,7 @@ u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
void
acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
{
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_ENTRY();
@@ -679,7 +679,6 @@ acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
info->prefix_node = node;
info->pathname = METHOD_NAME__SRS;
info->parameters = args;
- info->parameter_type = ACPI_PARAM_ARGS;
info->flags = ACPI_IGNORE_RETURN_VALUE;
/*
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 6d85289f1c1..5b049cd7955 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -6,6 +6,8 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/signal.h>
+#include <linux/kthread.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
@@ -92,17 +94,37 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
-static int acpi_eject_operation(acpi_handle handle, int lockable)
+static int acpi_bus_hot_remove_device(void *context)
{
+ struct acpi_device *device;
+ acpi_handle handle = context;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
- /*
- * TBD: evaluate _PS3?
- */
+ if (acpi_bus_get_device(handle, &device))
+ return 0;
- if (lockable) {
+ if (!device)
+ return 0;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Hot-removing device %s...\n", device->dev.bus_id));
+
+
+ if (acpi_bus_trim(device, 1)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Removing device failed\n"));
+ return -1;
+ }
+
+ /* power off device */
+ status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Power-off device failed\n"));
+
+ if (device->flags.lockable) {
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
@@ -118,26 +140,22 @@ static int acpi_eject_operation(acpi_handle handle, int lockable)
/*
* TBD: _EJD support.
*/
-
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- return (-ENODEV);
- }
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
- return (0);
+ return 0;
}
static ssize_t
acpi_eject_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t count)
{
- int result;
int ret = count;
- int islockable;
acpi_status status;
- acpi_handle handle;
acpi_object_type type = 0;
struct acpi_device *acpi_device = to_acpi_device(d);
+ struct task_struct *task;
if ((!count) || (buf[0] != '1')) {
return -EINVAL;
@@ -154,18 +172,12 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
goto err;
}
- islockable = acpi_device->flags.lockable;
- handle = acpi_device->handle;
-
- result = acpi_bus_trim(acpi_device, 1);
-
- if (!result)
- result = acpi_eject_operation(handle, islockable);
-
- if (result) {
- ret = -EBUSY;
- }
- err:
+ /* remove the device in another thread to fix the deadlock issue */
+ task = kthread_run(acpi_bus_hot_remove_device,
+ acpi_device->handle, "acpi_hot_remove_device");
+ if (IS_ERR(task))
+ ret = PTR_ERR(task);
+err:
return ret;
}
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 495c63a3e0a..244e352f766 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -61,8 +61,6 @@ static u32 acpi_suspend_states[] = {
[PM_SUSPEND_MAX] = ACPI_STATE_S5
};
-static int init_8259A_after_S1;
-
/**
* acpi_suspend_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported.
@@ -185,13 +183,6 @@ static void acpi_suspend_finish(void)
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
acpi_target_sleep_state = ACPI_STATE_S0;
-
-#ifdef CONFIG_X86
- if (init_8259A_after_S1) {
- printk("Broken toshiba laptop -> kicking interrupts\n");
- init_8259A(0);
- }
-#endif
}
/**
@@ -231,26 +222,6 @@ static struct platform_suspend_ops acpi_suspend_ops = {
.finish = acpi_suspend_finish,
.end = acpi_suspend_end,
};
-
-/*
- * Toshiba fails to preserve interrupts over S1, reinitialization
- * of 8259 is needed after S1 resume.
- */
-static int __init init_ints_after_s1(const struct dmi_system_id *d)
-{
- printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
- init_8259A_after_S1 = 1;
- return 0;
-}
-
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
- {
- .callback = init_ints_after_s1,
- .ident = "Toshiba Satellite 4030cdt",
- .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
- },
- {},
-};
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
@@ -368,8 +339,8 @@ int acpi_suspend(u32 acpi_state)
/**
* acpi_pm_device_sleep_state - return preferred power state of ACPI device
* in the system sleep state given by %acpi_target_sleep_state
- * @dev: device to examine
- * @wake: if set, the device should be able to wake up the system
+ * @dev: device to examine; its driver model wakeup flags control
+ * whether it should be able to wake up the system
* @d_min_p: used to store the upper limit of allowed states range
* Return value: preferred power state of the device on success, -ENODEV on
* failure (ie. if there's no 'struct acpi_device' for @dev)
@@ -387,7 +358,7 @@ int acpi_suspend(u32 acpi_state)
* via @wake.
*/
-int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
+int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
{
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev;
@@ -426,7 +397,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
* can wake the system. _S0W may be valid, too.
*/
if (acpi_target_sleep_state == ACPI_STATE_S0 ||
- (wake && adev->wakeup.state.enabled &&
+ (device_may_wakeup(dev) && adev->wakeup.state.enabled &&
adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
acpi_status status;
@@ -472,8 +443,6 @@ int __init acpi_sleep_init(void)
u8 type_a, type_b;
#ifdef CONFIG_SUSPEND
int i = 0;
-
- dmi_check_system(acpisleep_dmi_table);
#endif
if (acpi_disabled)
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 5bd2dec9a7a..d8e3f153b29 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -167,7 +167,13 @@ static int acpi_system_sysfs_init(void)
#define COUNT_ERROR 2 /* other */
#define NUM_COUNTERS_EXTRA 3
-static u32 *all_counters;
+#define ACPI_EVENT_VALID 0x01
+struct event_counter {
+ u32 count;
+ u32 flags;
+};
+
+static struct event_counter *all_counters;
static u32 num_gpes;
static u32 num_counters;
static struct attribute **all_attrs;
@@ -202,9 +208,44 @@ static int count_num_gpes(void)
return count;
}
+static int get_gpe_device(int index, acpi_handle *handle)
+{
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+ struct acpi_gpe_block_info *gpe_block;
+ acpi_cpu_flags flags;
+ struct acpi_namespace_node *node;
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+ while (gpe_xrupt_info) {
+ gpe_block = gpe_xrupt_info->gpe_block_list_head;
+ node = gpe_block->node;
+ while (gpe_block) {
+ index -= gpe_block->register_count *
+ ACPI_GPE_REGISTER_WIDTH;
+ if (index < 0) {
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ /* return NULL if it's FADT GPE */
+ if (node->type != ACPI_TYPE_DEVICE)
+ *handle = NULL;
+ else
+ *handle = node;
+ return 0;
+ }
+ node = gpe_block->node;
+ gpe_block = gpe_block->next;
+ }
+ gpe_xrupt_info = gpe_xrupt_info->next;
+ }
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+ return -ENODEV;
+}
+
static void delete_gpe_attr_array(void)
{
- u32 *tmp = all_counters;
+ struct event_counter *tmp = all_counters;
all_counters = NULL;
kfree(tmp);
@@ -230,9 +271,10 @@ void acpi_os_gpe_count(u32 gpe_number)
return;
if (gpe_number < num_gpes)
- all_counters[gpe_number]++;
+ all_counters[gpe_number].count++;
else
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR].
+ count++;
return;
}
@@ -243,44 +285,144 @@ void acpi_os_fixed_event_count(u32 event_number)
return;
if (event_number < ACPI_NUM_FIXED_EVENTS)
- all_counters[num_gpes + event_number]++;
+ all_counters[num_gpes + event_number].count++;
else
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR].
+ count++;
return;
}
+static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle)
+{
+ int result = 0;
+
+ if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
+ goto end;
+
+ if (index < num_gpes) {
+ result = get_gpe_device(index, handle);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
+ "Invalid GPE 0x%x\n", index));
+ goto end;
+ }
+ result = acpi_get_gpe_status(*handle, index,
+ ACPI_NOT_ISR, status);
+ } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS))
+ result = acpi_get_event_status(index - num_gpes, status);
+
+ /*
+ * sleep/power button GPE/Fixed Event is enabled after acpi_system_init,
+ * check the status at runtime and mark it as valid once it's enabled
+ */
+ if (!result && (*status & ACPI_EVENT_FLAG_ENABLED))
+ all_counters[index].flags |= ACPI_EVENT_VALID;
+end:
+ return result;
+}
+
static ssize_t counter_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
+ int index = attr - counter_attrs;
+ int size;
+ acpi_handle handle;
+ acpi_event_status status;
+ int result = 0;
+
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI].count =
acpi_irq_handled;
- all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
+ all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE].count =
acpi_gpe_count;
- return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
+ size = sprintf(buf, "%8d", all_counters[index].count);
+
+ /* "gpe_all" or "sci" */
+ if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
+ goto end;
+
+ result = get_status(index, &status, &handle);
+ if (result)
+ goto end;
+
+ if (!(all_counters[index].flags & ACPI_EVENT_VALID))
+ size += sprintf(buf + size, " invalid");
+ else if (status & ACPI_EVENT_FLAG_ENABLED)
+ size += sprintf(buf + size, " enable");
+ else
+ size += sprintf(buf + size, " disable");
+
+end:
+ size += sprintf(buf + size, "\n");
+ return result ? result : size;
}
/*
* counter_set() sets the specified counter.
* setting the total "sci" file to any value clears all counters.
+ * enable/disable/clear a gpe/fixed event in user space.
*/
static ssize_t counter_set(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t size)
{
int index = attr - counter_attrs;
+ acpi_event_status status;
+ acpi_handle handle;
+ int result = 0;
if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
int i;
for (i = 0; i < num_counters; ++i)
- all_counters[i] = 0;
+ all_counters[i].count = 0;
acpi_gpe_count = 0;
acpi_irq_handled = 0;
+ goto end;
+ }
+ /* show the event status for both GPEs and Fixed Events */
+ result = get_status(index, &status, &handle);
+ if (result)
+ goto end;
+
+ if (!(all_counters[index].flags & ACPI_EVENT_VALID)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Can not change Invalid GPE/Fixed Event status\n"));
+ return -EINVAL;
+ }
+
+ if (index < num_gpes) {
+ if (!strcmp(buf, "disable\n") &&
+ (status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_disable_gpe(handle, index, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "enable\n") &&
+ !(status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_enable_gpe(handle, index, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "clear\n") &&
+ (status & ACPI_EVENT_FLAG_SET))
+ result = acpi_clear_gpe(handle, index, ACPI_NOT_ISR);
+ else
+ all_counters[index].count = strtoul(buf, NULL, 0);
+ } else if (index < num_gpes + ACPI_NUM_FIXED_EVENTS) {
+ int event = index - num_gpes;
+ if (!strcmp(buf, "disable\n") &&
+ (status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_disable_event(event, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "enable\n") &&
+ !(status & ACPI_EVENT_FLAG_ENABLED))
+ result = acpi_enable_event(event, ACPI_NOT_ISR);
+ else if (!strcmp(buf, "clear\n") &&
+ (status & ACPI_EVENT_FLAG_SET))
+ result = acpi_clear_event(event);
+ else
+ all_counters[index].count = strtoul(buf, NULL, 0);
} else
- all_counters[index] = strtoul(buf, NULL, 0);
+ all_counters[index].count = strtoul(buf, NULL, 0);
- return size;
+ if (ACPI_FAILURE(result))
+ result = -EINVAL;
+end:
+ return result ? result : size;
}
void acpi_irq_stats_init(void)
@@ -298,7 +440,8 @@ void acpi_irq_stats_init(void)
if (all_attrs == NULL)
return;
- all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
+ all_counters = kzalloc(sizeof(struct event_counter) * (num_counters),
+ GFP_KERNEL);
if (all_counters == NULL)
goto fail;
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 949d4114eb9..ccb5b64bbef 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -124,7 +124,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
static void inline
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
- u8 bit_width, u64 address)
+ u8 byte_width, u64 address)
{
/*
@@ -136,7 +136,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
/* All other fields are byte-wide */
generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- generic_address->bit_width = bit_width;
+ generic_address->bit_width = byte_width << 3;
generic_address->bit_offset = 0;
generic_address->access_width = 0;
}
@@ -155,7 +155,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
*
******************************************************************************/
-void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
+void acpi_tb_parse_fadt(u32 table_index, u8 flags)
{
u32 length;
struct acpi_table_header *table;
@@ -280,7 +280,7 @@ static void acpi_tb_convert_fadt(void)
{
u8 pm1_register_length;
struct acpi_generic_address *target;
- acpi_native_uint i;
+ u32 i;
/* Update the local FADT table header length */
@@ -343,9 +343,11 @@ static void acpi_tb_convert_fadt(void)
*
* The PM event blocks are split into two register blocks, first is the
* PM Status Register block, followed immediately by the PM Enable Register
- * block. Each is of length (pm1_event_length/2)
+ * block. Each is of length (xpm1x_event_block.bit_width/2)
*/
- pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
+ WARN_ON(ACPI_MOD_16(acpi_gbl_FADT.xpm1a_event_block.bit_width));
+ pm1_register_length = (u8) ACPI_DIV_16(acpi_gbl_FADT
+ .xpm1a_event_block.bit_width);
/* The PM1A register block is required */
@@ -360,14 +362,17 @@ static void acpi_tb_convert_fadt(void)
/* The PM1B register block is optional, ignore if not present */
if (acpi_gbl_FADT.xpm1b_event_block.address) {
+ WARN_ON(ACPI_MOD_16(acpi_gbl_FADT.xpm1b_event_block.bit_width));
+ pm1_register_length = (u8) ACPI_DIV_16(acpi_gbl_FADT
+ .xpm1b_event_block
+ .bit_width);
acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
pm1_register_length,
(acpi_gbl_FADT.xpm1b_event_block.
address + pm1_register_length));
/* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1b_enable.space_id =
- acpi_gbl_FADT.xpm1a_event_block.space_id;
-
+ acpi_gbl_FADT.xpm1b_event_block.space_id;
}
}
@@ -396,7 +401,7 @@ static void acpi_tb_validate_fadt(void)
u32 *address32;
struct acpi_generic_address *address64;
u8 length;
- acpi_native_uint i;
+ u32 i;
/* Examine all of the 64-bit extended address fields (X fields) */
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
index 9ca3afc98c8..531584defbb 100644
--- a/drivers/acpi/tables/tbfind.c
+++ b/drivers/acpi/tables/tbfind.c
@@ -65,10 +65,9 @@ ACPI_MODULE_NAME("tbfind")
******************************************************************************/
acpi_status
acpi_tb_find_table(char *signature,
- char *oem_id,
- char *oem_table_id, acpi_native_uint * table_index)
+ char *oem_id, char *oem_table_id, u32 *table_index)
{
- acpi_native_uint i;
+ u32 i;
acpi_status status;
struct acpi_table_header header;
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 5336ce88f89..b22185f55a1 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -107,11 +107,10 @@ acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
******************************************************************************/
acpi_status
-acpi_tb_add_table(struct acpi_table_desc *table_desc,
- acpi_native_uint * table_index)
+acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
{
- acpi_native_uint i;
- acpi_native_uint length;
+ u32 i;
+ u32 length;
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_add_table);
@@ -207,8 +206,8 @@ acpi_status acpi_tb_resize_root_table_list(void)
/* Increase the Table Array size */
- tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
- ACPI_ROOT_TABLE_SIZE_INCREMENT)
+ tables = ACPI_ALLOCATE_ZEROED(((acpi_size) acpi_gbl_root_table_list.
+ size + ACPI_ROOT_TABLE_SIZE_INCREMENT)
* sizeof(struct acpi_table_desc));
if (!tables) {
ACPI_ERROR((AE_INFO,
@@ -220,7 +219,7 @@ acpi_status acpi_tb_resize_root_table_list(void)
if (acpi_gbl_root_table_list.tables) {
ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
- acpi_gbl_root_table_list.size *
+ (acpi_size) acpi_gbl_root_table_list.size *
sizeof(struct acpi_table_desc));
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
@@ -253,7 +252,7 @@ acpi_status acpi_tb_resize_root_table_list(void)
acpi_status
acpi_tb_store_table(acpi_physical_address address,
struct acpi_table_header *table,
- u32 length, u8 flags, acpi_native_uint * table_index)
+ u32 length, u8 flags, u32 *table_index)
{
acpi_status status = AE_OK;
@@ -334,7 +333,7 @@ void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
void acpi_tb_terminate(void)
{
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(tb_terminate);
@@ -374,7 +373,7 @@ void acpi_tb_terminate(void)
*
******************************************************************************/
-void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
+void acpi_tb_delete_namespace_by_owner(u32 table_index)
{
acpi_owner_id owner_id;
@@ -403,7 +402,7 @@ void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
*
******************************************************************************/
-acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
+acpi_status acpi_tb_allocate_owner_id(u32 table_index)
{
acpi_status status = AE_BAD_PARAMETER;
@@ -431,7 +430,7 @@ acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
*
******************************************************************************/
-acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
+acpi_status acpi_tb_release_owner_id(u32 table_index)
{
acpi_status status = AE_BAD_PARAMETER;
@@ -462,8 +461,7 @@ acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
*
******************************************************************************/
-acpi_status
-acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
+acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id)
{
acpi_status status = AE_BAD_PARAMETER;
@@ -490,7 +488,7 @@ acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
*
******************************************************************************/
-u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
+u8 acpi_tb_is_table_loaded(u32 table_index)
{
u8 is_loaded = FALSE;
@@ -518,7 +516,7 @@ u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
*
******************************************************************************/
-void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
{
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index bc019b9b6a6..0cc92ef5236 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -49,8 +49,8 @@ ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
static acpi_physical_address
-acpi_tb_get_root_table_entry(u8 * table_entry,
- acpi_native_uint table_entry_size);
+acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
+
/*******************************************************************************
*
* FUNCTION: acpi_tb_check_xsdt
@@ -238,7 +238,7 @@ acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
*
******************************************************************************/
-u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
+u8 acpi_tb_checksum(u8 *buffer, u32 length)
{
u8 sum = 0;
u8 *end = buffer + length;
@@ -268,7 +268,7 @@ u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
void
acpi_tb_install_table(acpi_physical_address address,
- u8 flags, char *signature, acpi_native_uint table_index)
+ u8 flags, char *signature, u32 table_index)
{
struct acpi_table_header *table;
@@ -336,8 +336,7 @@ acpi_tb_install_table(acpi_physical_address address,
******************************************************************************/
static acpi_physical_address
-acpi_tb_get_root_table_entry(u8 * table_entry,
- acpi_native_uint table_entry_size)
+acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
{
u64 address64;
@@ -395,8 +394,8 @@ acpi_status __init
acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
{
struct acpi_table_rsdp *rsdp;
- acpi_native_uint table_entry_size;
- acpi_native_uint i;
+ u32 table_entry_size;
+ u32 i;
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 0e319604d3e..fd7770aa106 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -125,7 +125,7 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
/* Root Table Array has been statically allocated by the host */
ACPI_MEMSET(initial_table_array, 0,
- initial_table_count *
+ (acpi_size) initial_table_count *
sizeof(struct acpi_table_desc));
acpi_gbl_root_table_list.tables = initial_table_array;
@@ -183,9 +183,9 @@ acpi_status acpi_reallocate_root_table(void)
return_ACPI_STATUS(AE_SUPPORT);
}
- new_size =
- (acpi_gbl_root_table_list.count +
- ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
+ new_size = ((acpi_size) acpi_gbl_root_table_list.count +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT) *
+ sizeof(struct acpi_table_desc);
/* Create new array and copy the old array */
@@ -222,7 +222,7 @@ acpi_status acpi_reallocate_root_table(void)
acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
{
acpi_status status;
- acpi_native_uint table_index;
+ u32 table_index;
struct acpi_table_desc table_desc;
if (!table_ptr)
@@ -264,11 +264,10 @@ ACPI_EXPORT_SYMBOL(acpi_load_table)
*****************************************************************************/
acpi_status
acpi_get_table_header(char *signature,
- acpi_native_uint instance,
- struct acpi_table_header * out_table_header)
+ u32 instance, struct acpi_table_header *out_table_header)
{
- acpi_native_uint i;
- acpi_native_uint j;
+ u32 i;
+ u32 j;
struct acpi_table_header *header;
/* Parameter validation */
@@ -378,10 +377,10 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
*****************************************************************************/
acpi_status
acpi_get_table(char *signature,
- acpi_native_uint instance, struct acpi_table_header **out_table)
+ u32 instance, struct acpi_table_header **out_table)
{
- acpi_native_uint i;
- acpi_native_uint j;
+ u32 i;
+ u32 j;
acpi_status status;
/* Parameter validation */
@@ -435,8 +434,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
*
******************************************************************************/
acpi_status
-acpi_get_table_by_index(acpi_native_uint table_index,
- struct acpi_table_header ** table)
+acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
{
acpi_status status;
@@ -493,7 +491,7 @@ static acpi_status acpi_tb_load_namespace(void)
{
acpi_status status;
struct acpi_table_header *table;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(tb_load_namespace);
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index b8c0dfa084f..2d157e0f98d 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -118,7 +118,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
*
******************************************************************************/
-acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
+acpi_status acpi_find_root_pointer(acpi_size *table_address)
{
u8 *table_ptr;
u8 *mem_rover;
@@ -153,7 +153,7 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
* 1b) Search EBDA paragraphs (EBDA is required to be a
* minimum of 1_k length)
*/
- table_ptr = acpi_os_map_memory((acpi_native_uint)
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
physical_address,
ACPI_EBDA_WINDOW_SIZE);
if (!table_ptr) {
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index ede084829a7..3dfb8a442b2 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -309,7 +309,8 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
*
******************************************************************************/
-void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line)
+void *acpi_ut_allocate(acpi_size size,
+ u32 component, const char *module, u32 line)
{
void *allocation;
@@ -353,7 +354,7 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line)
******************************************************************************/
void *acpi_ut_allocate_zeroed(acpi_size size,
- u32 component, char *module, u32 line)
+ u32 component, const char *module, u32 line)
{
void *allocation;
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 655c290aca7..53499ac9098 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -572,7 +572,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object,
acpi_status status = AE_OK;
union acpi_operand_object *package_object;
union acpi_operand_object **package_elements;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(ut_copy_epackage_to_ipackage);
@@ -599,7 +599,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object,
/* Truncate package and delete it */
- package_object->package.count = (u32) i;
+ package_object->package.count = i;
package_elements[i] = NULL;
acpi_ut_remove_reference(package_object);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index f938f465efa..fd66ecb6741 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -157,7 +157,8 @@ void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print(u32 requested_debug_level,
u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, char *format, ...)
+ const char *module_name,
+ u32 component_id, const char *format, ...)
{
acpi_thread_id thread_id;
va_list args;
@@ -228,7 +229,8 @@ void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print_raw(u32 requested_debug_level,
u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, char *format, ...)
+ const char *module_name,
+ u32 component_id, const char *format, ...)
{
va_list args;
@@ -261,7 +263,8 @@ ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw)
******************************************************************************/
void
acpi_ut_trace(u32 line_number,
- const char *function_name, char *module_name, u32 component_id)
+ const char *function_name,
+ const char *module_name, u32 component_id)
{
acpi_gbl_nesting_level++;
@@ -293,7 +296,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_trace)
void
acpi_ut_trace_ptr(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, void *pointer)
+ const char *module_name, u32 component_id, void *pointer)
{
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
@@ -324,7 +327,7 @@ acpi_ut_trace_ptr(u32 line_number,
void
acpi_ut_trace_str(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, char *string)
+ const char *module_name, u32 component_id, char *string)
{
acpi_gbl_nesting_level++;
@@ -356,7 +359,7 @@ acpi_ut_trace_str(u32 line_number,
void
acpi_ut_trace_u32(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, u32 integer)
+ const char *module_name, u32 component_id, u32 integer)
{
acpi_gbl_nesting_level++;
@@ -386,7 +389,8 @@ acpi_ut_trace_u32(u32 line_number,
void
acpi_ut_exit(u32 line_number,
- const char *function_name, char *module_name, u32 component_id)
+ const char *function_name,
+ const char *module_name, u32 component_id)
{
acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
@@ -417,7 +421,8 @@ ACPI_EXPORT_SYMBOL(acpi_ut_exit)
void
acpi_ut_status_exit(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, acpi_status status)
+ const char *module_name,
+ u32 component_id, acpi_status status)
{
if (ACPI_SUCCESS(status)) {
@@ -458,7 +463,8 @@ ACPI_EXPORT_SYMBOL(acpi_ut_status_exit)
void
acpi_ut_value_exit(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, acpi_integer value)
+ const char *module_name,
+ u32 component_id, acpi_integer value)
{
acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
@@ -490,7 +496,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_value_exit)
void
acpi_ut_ptr_exit(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, u8 * ptr)
+ const char *module_name, u32 component_id, u8 *ptr)
{
acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
@@ -519,8 +525,8 @@ acpi_ut_ptr_exit(u32 line_number,
void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
{
- acpi_native_uint i = 0;
- acpi_native_uint j;
+ u32 i = 0;
+ u32 j;
u32 temp32;
u8 buf_char;
@@ -539,7 +545,7 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
/* Print current offset */
- acpi_os_printf("%6.4X: ", (u32) i);
+ acpi_os_printf("%6.4X: ", i);
/* Print 16 hex chars */
@@ -549,7 +555,7 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
/* Dump fill spaces */
acpi_os_printf("%*s", ((display * 2) + 1), " ");
- j += (acpi_native_uint) display;
+ j += display;
continue;
}
@@ -557,32 +563,38 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
case DB_BYTE_DISPLAY:
default: /* Default is BYTE display */
- acpi_os_printf("%02X ", buffer[i + j]);
+ acpi_os_printf("%02X ",
+ buffer[(acpi_size) i + j]);
break;
case DB_WORD_DISPLAY:
- ACPI_MOVE_16_TO_32(&temp32, &buffer[i + j]);
+ ACPI_MOVE_16_TO_32(&temp32,
+ &buffer[(acpi_size) i + j]);
acpi_os_printf("%04X ", temp32);
break;
case DB_DWORD_DISPLAY:
- ACPI_MOVE_32_TO_32(&temp32, &buffer[i + j]);
+ ACPI_MOVE_32_TO_32(&temp32,
+ &buffer[(acpi_size) i + j]);
acpi_os_printf("%08X ", temp32);
break;
case DB_QWORD_DISPLAY:
- ACPI_MOVE_32_TO_32(&temp32, &buffer[i + j]);
+ ACPI_MOVE_32_TO_32(&temp32,
+ &buffer[(acpi_size) i + j]);
acpi_os_printf("%08X", temp32);
- ACPI_MOVE_32_TO_32(&temp32, &buffer[i + j + 4]);
+ ACPI_MOVE_32_TO_32(&temp32,
+ &buffer[(acpi_size) i + j +
+ 4]);
acpi_os_printf("%08X ", temp32);
break;
}
- j += (acpi_native_uint) display;
+ j += display;
}
/*
@@ -596,7 +608,7 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display)
return;
}
- buf_char = buffer[i + j];
+ buf_char = buffer[(acpi_size) i + j];
if (ACPI_IS_PRINT(buf_char)) {
acpi_os_printf("%c", buf_char);
} else {
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 1fbc35139e8..c5c791a575c 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -442,7 +442,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
union acpi_generic_state *state_list = NULL;
union acpi_operand_object *next_object = NULL;
union acpi_generic_state *state;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE_PTR(ut_update_object_reference, object);
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 05e61be267d..352747e49c7 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -97,7 +97,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
acpi_status status;
union acpi_operand_object *string_desc;
union acpi_operand_object *return_desc;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(ut_osi_implementation);
@@ -217,7 +217,6 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
info->prefix_node = prefix_node;
info->pathname = path;
- info->parameter_type = ACPI_PARAM_ARGS;
/* Evaluate the object/method */
@@ -514,7 +513,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node,
u32 count;
u32 size;
struct acpi_compatible_id_list *cid_list;
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_TRACE(ut_execute_CID);
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 1f057b71db1..f34be677355 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -64,7 +64,7 @@ ACPI_MODULE_NAME("utmisc")
******************************************************************************/
const char *acpi_ut_validate_exception(acpi_status status)
{
- acpi_status sub_status;
+ u32 sub_status;
const char *exception = NULL;
ACPI_FUNCTION_ENTRY();
@@ -85,32 +85,28 @@ const char *acpi_ut_validate_exception(acpi_status status)
case AE_CODE_PROGRAMMER:
if (sub_status <= AE_CODE_PGM_MAX) {
- exception =
- acpi_gbl_exception_names_pgm[sub_status - 1];
+ exception = acpi_gbl_exception_names_pgm[sub_status];
}
break;
case AE_CODE_ACPI_TABLES:
if (sub_status <= AE_CODE_TBL_MAX) {
- exception =
- acpi_gbl_exception_names_tbl[sub_status - 1];
+ exception = acpi_gbl_exception_names_tbl[sub_status];
}
break;
case AE_CODE_AML:
if (sub_status <= AE_CODE_AML_MAX) {
- exception =
- acpi_gbl_exception_names_aml[sub_status - 1];
+ exception = acpi_gbl_exception_names_aml[sub_status];
}
break;
case AE_CODE_CONTROL:
if (sub_status <= AE_CODE_CTRL_MAX) {
- exception =
- acpi_gbl_exception_names_ctrl[sub_status - 1];
+ exception = acpi_gbl_exception_names_ctrl[sub_status];
}
break;
@@ -165,9 +161,9 @@ u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
{
- acpi_native_uint i;
- acpi_native_uint j;
- acpi_native_uint k;
+ u32 i;
+ u32 j;
+ u32 k;
acpi_status status;
ACPI_FUNCTION_TRACE(ut_allocate_owner_id);
@@ -273,7 +269,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
{
acpi_owner_id owner_id = *owner_id_ptr;
acpi_status status;
- acpi_native_uint index;
+ u32 index;
u32 bit;
ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id);
@@ -593,7 +589,7 @@ acpi_ut_display_init_pathname(u8 type,
*
******************************************************************************/
-u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position)
+u8 acpi_ut_valid_acpi_char(char character, u32 position)
{
if (!((character >= 'A' && character <= 'Z') ||
@@ -628,7 +624,7 @@ u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position)
u8 acpi_ut_valid_acpi_name(u32 name)
{
- acpi_native_uint i;
+ u32 i;
ACPI_FUNCTION_ENTRY();
@@ -657,7 +653,7 @@ u8 acpi_ut_valid_acpi_name(u32 name)
acpi_name acpi_ut_repair_name(char *name)
{
- acpi_native_uint i;
+ u32 i;
char new_name[ACPI_NAME_SIZE];
for (i = 0; i < ACPI_NAME_SIZE; i++) {
@@ -1024,7 +1020,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
******************************************************************************/
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_error(char *module_name, u32 line_number, char *format, ...)
+acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...)
{
va_list args;
@@ -1037,8 +1033,8 @@ acpi_ut_error(char *module_name, u32 line_number, char *format, ...)
}
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_exception(char *module_name,
- u32 line_number, acpi_status status, char *format, ...)
+acpi_ut_exception(const char *module_name,
+ u32 line_number, acpi_status status, const char *format, ...)
{
va_list args;
@@ -1054,7 +1050,8 @@ acpi_ut_exception(char *module_name,
EXPORT_SYMBOL(acpi_ut_exception);
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
+acpi_ut_warning(const char *module_name,
+ u32 line_number, const char *format, ...)
{
va_list args;
@@ -1067,7 +1064,7 @@ acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
}
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
+acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...)
{
va_list args;
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index f7d602b1a89..7331dde9e1b 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -218,7 +218,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
* the mutex ordering rule. This indicates a coding error somewhere in
* the ACPI subsystem code.
*/
- for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) {
+ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
if (i == mutex_id) {
ACPI_ERROR((AE_INFO,
@@ -315,7 +315,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
* ordering rule. This indicates a coding error somewhere in
* the ACPI subsystem code.
*/
- for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) {
+ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
if (i == mutex_id) {
continue;
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index e68466de804..e25484495e6 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -83,7 +83,8 @@ acpi_ut_get_element_length(u8 object_type,
*
******************************************************************************/
-union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name,
+union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char
+ *module_name,
u32 line_number,
u32 component_id,
acpi_object_type
@@ -175,8 +176,8 @@ union acpi_operand_object *acpi_ut_create_package_object(u32 count)
* Create the element array. Count+1 allows the array to be null
* terminated.
*/
- package_elements = ACPI_ALLOCATE_ZEROED((acpi_size)
- (count + 1) * sizeof(void *));
+ package_elements = ACPI_ALLOCATE_ZEROED(((acpi_size) count +
+ 1) * sizeof(void *));
if (!package_elements) {
acpi_ut_remove_reference(package_desc);
return_PTR(NULL);
@@ -347,7 +348,7 @@ u8 acpi_ut_valid_internal_object(void *object)
*
******************************************************************************/
-void *acpi_ut_allocate_object_desc_dbg(char *module_name,
+void *acpi_ut_allocate_object_desc_dbg(const char *module_name,
u32 line_number, u32 component_id)
{
union acpi_operand_object *object;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index d089c4519d4..64c889331f3 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -631,6 +631,76 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
* device : video output device (LCD, CRT, ..)
*
* Return Value:
+ * Maximum brightness level
+ *
+ * Allocate and initialize device->brightness.
+ */
+
+static int
+acpi_video_init_brightness(struct acpi_video_device *device)
+{
+ union acpi_object *obj = NULL;
+ int i, max_level = 0, count = 0;
+ union acpi_object *o;
+ struct acpi_video_device_brightness *br = NULL;
+
+ if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
+ "LCD brightness level\n"));
+ goto out;
+ }
+
+ if (obj->package.count < 2)
+ goto out;
+
+ br = kzalloc(sizeof(*br), GFP_KERNEL);
+ if (!br) {
+ printk(KERN_ERR "can't allocate memory\n");
+ goto out;
+ }
+
+ br->levels = kmalloc(obj->package.count * sizeof *(br->levels),
+ GFP_KERNEL);
+ if (!br->levels)
+ goto out_free;
+
+ for (i = 0; i < obj->package.count; i++) {
+ o = (union acpi_object *)&obj->package.elements[i];
+ if (o->type != ACPI_TYPE_INTEGER) {
+ printk(KERN_ERR PREFIX "Invalid data\n");
+ continue;
+ }
+ br->levels[count] = (u32) o->integer.value;
+
+ if (br->levels[count] > max_level)
+ max_level = br->levels[count];
+ count++;
+ }
+
+ if (count < 2)
+ goto out_free_levels;
+
+ br->count = count;
+ device->brightness = br;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count));
+ kfree(obj);
+ return max_level;
+
+out_free_levels:
+ kfree(br->levels);
+out_free:
+ kfree(br);
+out:
+ device->brightness = NULL;
+ kfree(obj);
+ return 0;
+}
+
+/*
+ * Arg:
+ * device : video output device (LCD, CRT, ..)
+ *
+ * Return Value:
* None
*
* Find out all required AML methods defined under the output
@@ -640,10 +710,7 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
static void acpi_video_device_find_cap(struct acpi_video_device *device)
{
acpi_handle h_dummy1;
- int i;
u32 max_level = 0;
- union acpi_object *obj = NULL;
- struct acpi_video_device_brightness *br = NULL;
memset(&device->cap, 0, sizeof(device->cap));
@@ -672,53 +739,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
device->cap._DSS = 1;
}
- if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
-
- if (obj->package.count >= 2) {
- int count = 0;
- union acpi_object *o;
-
- br = kzalloc(sizeof(*br), GFP_KERNEL);
- if (!br) {
- printk(KERN_ERR "can't allocate memory\n");
- } else {
- br->levels = kmalloc(obj->package.count *
- sizeof *(br->levels), GFP_KERNEL);
- if (!br->levels)
- goto out;
-
- for (i = 0; i < obj->package.count; i++) {
- o = (union acpi_object *)&obj->package.
- elements[i];
- if (o->type != ACPI_TYPE_INTEGER) {
- printk(KERN_ERR PREFIX "Invalid data\n");
- continue;
- }
- br->levels[count] = (u32) o->integer.value;
-
- if (br->levels[count] > max_level)
- max_level = br->levels[count];
- count++;
- }
- out:
- if (count < 2) {
- kfree(br->levels);
- kfree(br);
- } else {
- br->count = count;
- device->brightness = br;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "found %d brightness levels\n",
- count));
- }
- }
- }
-
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
- }
-
- kfree(obj);
+ max_level = acpi_video_init_brightness(device);
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
int result;
@@ -1695,6 +1716,8 @@ static void
acpi_video_switch_brightness(struct acpi_video_device *device, int event)
{
unsigned long level_current, level_next;
+ if (!device->brightness)
+ return;
acpi_video_device_lcd_get_level_current(device, &level_current);
level_next = acpi_video_get_next_level(device, level_current, event);
acpi_video_device_lcd_set_level(device, level_next);
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index da8a1658a27..aaca40283be 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -59,6 +59,55 @@ struct apm_queue {
};
/*
+ * thread states (for threads using a writable /dev/apm_bios fd):
+ *
+ * SUSPEND_NONE: nothing happening
+ * SUSPEND_PENDING: suspend event queued for thread and pending to be read
+ * SUSPEND_READ: suspend event read, pending acknowledgement
+ * SUSPEND_ACKED: acknowledgement received from thread (via ioctl),
+ * waiting for resume
+ * SUSPEND_ACKTO: acknowledgement timeout
+ * SUSPEND_DONE: thread had acked suspend and is now notified of
+ * resume
+ *
+ * SUSPEND_WAIT: this thread invoked suspend and is waiting for resume
+ *
+ * A thread migrates in one of three paths:
+ * NONE -1-> PENDING -2-> READ -3-> ACKED -4-> DONE -5-> NONE
+ * -6-> ACKTO -7-> NONE
+ * NONE -8-> WAIT -9-> NONE
+ *
+ * While in PENDING or READ, the thread is accounted for in the
+ * suspend_acks_pending counter.
+ *
+ * The transitions are invoked as follows:
+ * 1: suspend event is signalled from the core PM code
+ * 2: the suspend event is read from the fd by the userspace thread
+ * 3: userspace thread issues the APM_IOC_SUSPEND ioctl (as ack)
+ * 4: core PM code signals that we have resumed
+ * 5: APM_IOC_SUSPEND ioctl returns
+ *
+ * 6: the notifier invoked from the core PM code timed out waiting
+ * for all relevant threds to enter ACKED state and puts those
+ * that haven't into ACKTO
+ * 7: those threads issue APM_IOC_SUSPEND ioctl too late,
+ * get an error
+ *
+ * 8: userspace thread issues the APM_IOC_SUSPEND ioctl (to suspend),
+ * ioctl code invokes pm_suspend()
+ * 9: pm_suspend() returns indicating resume
+ */
+enum apm_suspend_state {
+ SUSPEND_NONE,
+ SUSPEND_PENDING,
+ SUSPEND_READ,
+ SUSPEND_ACKED,
+ SUSPEND_ACKTO,
+ SUSPEND_WAIT,
+ SUSPEND_DONE,
+};
+
+/*
* The per-file APM data
*/
struct apm_user {
@@ -69,13 +118,7 @@ struct apm_user {
unsigned int reader: 1;
int suspend_result;
- unsigned int suspend_state;
-#define SUSPEND_NONE 0 /* no suspend pending */
-#define SUSPEND_PENDING 1 /* suspend pending read */
-#define SUSPEND_READ 2 /* suspend read, pending ack */
-#define SUSPEND_ACKED 3 /* suspend acked */
-#define SUSPEND_WAIT 4 /* waiting for suspend */
-#define SUSPEND_DONE 5 /* suspend completed */
+ enum apm_suspend_state suspend_state;
struct apm_queue queue;
};
@@ -83,7 +126,8 @@ struct apm_user {
/*
* Local variables
*/
-static int suspends_pending;
+static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
+static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
static int apm_disabled;
static struct task_struct *kapmd_tsk;
@@ -166,78 +210,6 @@ static void queue_event(apm_event_t event)
wake_up_interruptible(&apm_waitqueue);
}
-/*
- * queue_suspend_event - queue an APM suspend event.
- *
- * Check that we're in a state where we can suspend. If not,
- * return -EBUSY. Otherwise, queue an event to all "writer"
- * users. If there are no "writer" users, return '1' to
- * indicate that we can immediately suspend.
- */
-static int queue_suspend_event(apm_event_t event, struct apm_user *sender)
-{
- struct apm_user *as;
- int ret = 1;
-
- mutex_lock(&state_lock);
- down_read(&user_list_lock);
-
- /*
- * If a thread is still processing, we can't suspend, so reject
- * the request.
- */
- list_for_each_entry(as, &apm_user_list, list) {
- if (as != sender && as->reader && as->writer && as->suser &&
- as->suspend_state != SUSPEND_NONE) {
- ret = -EBUSY;
- goto out;
- }
- }
-
- list_for_each_entry(as, &apm_user_list, list) {
- if (as != sender && as->reader && as->writer && as->suser) {
- as->suspend_state = SUSPEND_PENDING;
- suspends_pending++;
- queue_add_event(&as->queue, event);
- ret = 0;
- }
- }
- out:
- up_read(&user_list_lock);
- mutex_unlock(&state_lock);
- wake_up_interruptible(&apm_waitqueue);
- return ret;
-}
-
-static void apm_suspend(void)
-{
- struct apm_user *as;
- int err = pm_suspend(PM_SUSPEND_MEM);
-
- /*
- * Anyone on the APM queues will think we're still suspended.
- * Send a message so everyone knows we're now awake again.
- */
- queue_event(APM_NORMAL_RESUME);
-
- /*
- * Finally, wake up anyone who is sleeping on the suspend.
- */
- mutex_lock(&state_lock);
- down_read(&user_list_lock);
- list_for_each_entry(as, &apm_user_list, list) {
- if (as->suspend_state == SUSPEND_WAIT ||
- as->suspend_state == SUSPEND_ACKED) {
- as->suspend_result = err;
- as->suspend_state = SUSPEND_DONE;
- }
- }
- up_read(&user_list_lock);
- mutex_unlock(&state_lock);
-
- wake_up(&apm_suspend_waitqueue);
-}
-
static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
{
struct apm_user *as = fp->private_data;
@@ -308,25 +280,22 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
as->suspend_result = -EINTR;
- if (as->suspend_state == SUSPEND_READ) {
- int pending;
-
+ switch (as->suspend_state) {
+ case SUSPEND_READ:
/*
* If we read a suspend command from /dev/apm_bios,
* then the corresponding APM_IOC_SUSPEND ioctl is
* interpreted as an acknowledge.
*/
as->suspend_state = SUSPEND_ACKED;
- suspends_pending--;
- pending = suspends_pending == 0;
+ atomic_dec(&suspend_acks_pending);
mutex_unlock(&state_lock);
/*
- * If there are no further acknowledges required,
- * suspend the system.
+ * suspend_acks_pending changed, the notifier needs to
+ * be woken up for this
*/
- if (pending)
- apm_suspend();
+ wake_up(&apm_suspend_waitqueue);
/*
* Wait for the suspend/resume to complete. If there
@@ -342,35 +311,21 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
* try_to_freeze() in freezer_count() will not trigger
*/
freezer_count();
- } else {
+ break;
+ case SUSPEND_ACKTO:
+ as->suspend_result = -ETIMEDOUT;
+ mutex_unlock(&state_lock);
+ break;
+ default:
as->suspend_state = SUSPEND_WAIT;
mutex_unlock(&state_lock);
/*
* Otherwise it is a request to suspend the system.
- * Queue an event for all readers, and expect an
- * acknowledge from all writers who haven't already
- * acknowledged.
- */
- err = queue_suspend_event(APM_USER_SUSPEND, as);
- if (err < 0) {
- /*
- * Avoid taking the lock here - this
- * should be fine.
- */
- as->suspend_state = SUSPEND_NONE;
- break;
- }
-
- if (err > 0)
- apm_suspend();
-
- /*
- * Wait for the suspend/resume to complete. If there
- * are pending acknowledges, we wait here for them.
+ * Just invoke pm_suspend(), we'll handle it from
+ * there via the notifier.
*/
- wait_event_freezable(apm_suspend_waitqueue,
- as->suspend_state == SUSPEND_DONE);
+ as->suspend_result = pm_suspend(PM_SUSPEND_MEM);
}
mutex_lock(&state_lock);
@@ -386,7 +341,6 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
static int apm_release(struct inode * inode, struct file * filp)
{
struct apm_user *as = filp->private_data;
- int pending = 0;
filp->private_data = NULL;
@@ -396,18 +350,15 @@ static int apm_release(struct inode * inode, struct file * filp)
/*
* We are now unhooked from the chain. As far as new
- * events are concerned, we no longer exist. However, we
- * need to balance suspends_pending, which means the
- * possibility of sleeping.
+ * events are concerned, we no longer exist.
*/
mutex_lock(&state_lock);
- if (as->suspend_state != SUSPEND_NONE) {
- suspends_pending -= 1;
- pending = suspends_pending == 0;
- }
+ if (as->suspend_state == SUSPEND_PENDING ||
+ as->suspend_state == SUSPEND_READ)
+ atomic_dec(&suspend_acks_pending);
mutex_unlock(&state_lock);
- if (pending)
- apm_suspend();
+
+ wake_up(&apm_suspend_waitqueue);
kfree(as);
return 0;
@@ -545,7 +496,6 @@ static int kapmd(void *arg)
{
do {
apm_event_t event;
- int ret;
wait_event_interruptible(kapmd_wait,
!queue_empty(&kapmd_queue) || kthread_should_stop());
@@ -570,20 +520,13 @@ static int kapmd(void *arg)
case APM_USER_SUSPEND:
case APM_SYS_SUSPEND:
- ret = queue_suspend_event(event, NULL);
- if (ret < 0) {
- /*
- * We were busy. Try again in 50ms.
- */
- queue_add_event(&kapmd_queue, event);
- msleep(50);
- }
- if (ret > 0)
- apm_suspend();
+ pm_suspend(PM_SUSPEND_MEM);
break;
case APM_CRITICAL_SUSPEND:
- apm_suspend();
+ atomic_inc(&userspace_notification_inhibit);
+ pm_suspend(PM_SUSPEND_MEM);
+ atomic_dec(&userspace_notification_inhibit);
break;
}
} while (1);
@@ -591,6 +534,120 @@ static int kapmd(void *arg)
return 0;
}
+static int apm_suspend_notifier(struct notifier_block *nb,
+ unsigned long event,
+ void *dummy)
+{
+ struct apm_user *as;
+ int err;
+
+ /* short-cut emergency suspends */
+ if (atomic_read(&userspace_notification_inhibit))
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ /*
+ * Queue an event to all "writer" users that we want
+ * to suspend and need their ack.
+ */
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->suspend_state != SUSPEND_WAIT && as->reader &&
+ as->writer && as->suser) {
+ as->suspend_state = SUSPEND_PENDING;
+ atomic_inc(&suspend_acks_pending);
+ queue_add_event(&as->queue, APM_USER_SUSPEND);
+ }
+ }
+
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+ wake_up_interruptible(&apm_waitqueue);
+
+ /*
+ * Wait for the the suspend_acks_pending variable to drop to
+ * zero, meaning everybody acked the suspend event (or the
+ * process was killed.)
+ *
+ * If the app won't answer within a short while we assume it
+ * locked up and ignore it.
+ */
+ err = wait_event_interruptible_timeout(
+ apm_suspend_waitqueue,
+ atomic_read(&suspend_acks_pending) == 0,
+ 5*HZ);
+
+ /* timed out */
+ if (err == 0) {
+ /*
+ * Move anybody who timed out to "ack timeout" state.
+ *
+ * We could time out and the userspace does the ACK
+ * right after we time out but before we enter the
+ * locked section here, but that's fine.
+ */
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->suspend_state == SUSPEND_PENDING ||
+ as->suspend_state == SUSPEND_READ) {
+ as->suspend_state = SUSPEND_ACKTO;
+ atomic_dec(&suspend_acks_pending);
+ }
+ }
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+ }
+
+ /* let suspend proceed */
+ if (err >= 0)
+ return NOTIFY_OK;
+
+ /* interrupted by signal */
+ return NOTIFY_BAD;
+
+ case PM_POST_SUSPEND:
+ /*
+ * Anyone on the APM queues will think we're still suspended.
+ * Send a message so everyone knows we're now awake again.
+ */
+ queue_event(APM_NORMAL_RESUME);
+
+ /*
+ * Finally, wake up anyone who is sleeping on the suspend.
+ */
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->suspend_state == SUSPEND_ACKED) {
+ /*
+ * TODO: maybe grab error code, needs core
+ * changes to push the error to the notifier
+ * chain (could use the second parameter if
+ * implemented)
+ */
+ as->suspend_result = 0;
+ as->suspend_state = SUSPEND_DONE;
+ }
+ }
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+
+ wake_up(&apm_suspend_waitqueue);
+ return NOTIFY_OK;
+
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static struct notifier_block apm_notif_block = {
+ .notifier_call = apm_suspend_notifier,
+};
+
static int __init apm_init(void)
{
int ret;
@@ -604,7 +661,7 @@ static int __init apm_init(void)
if (IS_ERR(kapmd_tsk)) {
ret = PTR_ERR(kapmd_tsk);
kapmd_tsk = NULL;
- return ret;
+ goto out;
}
wake_up_process(kapmd_tsk);
@@ -613,16 +670,27 @@ static int __init apm_init(void)
#endif
ret = misc_register(&apm_device);
- if (ret != 0) {
- remove_proc_entry("apm", NULL);
- kthread_stop(kapmd_tsk);
- }
+ if (ret)
+ goto out_stop;
+ ret = register_pm_notifier(&apm_notif_block);
+ if (ret)
+ goto out_unregister;
+
+ return 0;
+
+ out_unregister:
+ misc_deregister(&apm_device);
+ out_stop:
+ remove_proc_entry("apm", NULL);
+ kthread_stop(kapmd_tsk);
+ out:
return ret;
}
static void __exit apm_exit(void)
{
+ unregister_pm_notifier(&apm_notif_block);
misc_deregister(&apm_device);
remove_proc_entry("apm", NULL);
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index 466b9ee9279..f97b5b35687 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -23,12 +23,9 @@
#include "lm75.h"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END };
-/* Insmod parameters */
-I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418);
+enum chips { ad7416, ad7417, ad7418 };
/* AD7418 registers */
#define AD7418_REG_TEMP_IN 0x00
@@ -46,7 +43,6 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
AD7418_REG_TEMP_OS };
struct ad7418_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct attribute_group attrs;
enum chips type;
@@ -58,16 +54,25 @@ struct ad7418_data {
u16 in[4];
};
-static int ad7418_attach_adapter(struct i2c_adapter *adapter);
-static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind);
-static int ad7418_detach_client(struct i2c_client *client);
+static int ad7418_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int ad7418_remove(struct i2c_client *client);
+
+static const struct i2c_device_id ad7418_id[] = {
+ { "ad7416", ad7416 },
+ { "ad7417", ad7417 },
+ { "ad7418", ad7418 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ad7418_id);
static struct i2c_driver ad7418_driver = {
.driver = {
.name = "ad7418",
},
- .attach_adapter = ad7418_attach_adapter,
- .detach_client = ad7418_detach_client,
+ .probe = ad7418_probe,
+ .remove = ad7418_remove,
+ .id_table = ad7418_id,
};
/* All registers are word-sized, except for the configuration registers.
@@ -192,13 +197,6 @@ static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
-static int ad7418_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, ad7418_detect);
-}
-
static struct attribute *ad7416_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
@@ -225,98 +223,46 @@ static struct attribute *ad7418_attributes[] = {
NULL
};
-static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
+static int ad7418_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct i2c_client *client;
+ struct i2c_adapter *adapter = client->adapter;
struct ad7418_data *data;
- int err = 0;
+ int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_WORD_DATA))
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ err = -EOPNOTSUPP;
goto exit;
+ }
if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- client = &data->client;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &ad7418_driver;
-
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
-
- /* AD7418 has a curious behaviour on registers 6 and 7. They
- * both always read 0xC071 and are not documented on the datasheet.
- * We use them to detect the chip.
- */
- if (kind <= 0) {
- int reg, reg6, reg7;
-
- /* the AD7416 lies within this address range, but I have
- * no means to check.
- */
- if (address >= 0x48 && address <= 0x4f) {
- /* XXX add tests for AD7416 here */
- /* data->type = ad7416; */
- }
- /* here we might have AD7417 or AD7418 */
- else if (address >= 0x28 && address <= 0x2f) {
- reg6 = i2c_smbus_read_word_data(client, 0x06);
- reg7 = i2c_smbus_read_word_data(client, 0x07);
-
- if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071)
- data->type = ad7418;
-
- /* XXX add tests for AD7417 here */
-
-
- /* both AD7417 and AD7418 have bits 0-5 of
- * the CONF2 register at 0
- */
- reg = i2c_smbus_read_byte_data(client,
- AD7418_REG_CONF2);
- if (reg & 0x3F)
- data->type = any_chip; /* detection failed */
- }
- } else {
- dev_dbg(&adapter->dev, "detection forced\n");
- }
-
- if (kind > 0)
- data->type = kind;
- else if (kind < 0 && data->type == any_chip) {
- err = -ENODEV;
- goto exit_free;
- }
+ data->type = id->driver_data;
switch (data->type) {
- case any_chip:
case ad7416:
data->adc_max = 0;
data->attrs.attrs = ad7416_attributes;
- strlcpy(client->name, "ad7416", I2C_NAME_SIZE);
break;
case ad7417:
data->adc_max = 4;
data->attrs.attrs = ad7417_attributes;
- strlcpy(client->name, "ad7417", I2C_NAME_SIZE);
break;
case ad7418:
data->adc_max = 1;
data->attrs.attrs = ad7418_attributes;
- strlcpy(client->name, "ad7418", I2C_NAME_SIZE);
break;
}
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
dev_info(&client->dev, "%s chip found\n", client->name);
/* Initialize the AD7418 chip */
@@ -324,7 +270,7 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -336,20 +282,17 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int ad7418_detach_client(struct i2c_client *client)
+static int ad7418_remove(struct i2c_client *client)
{
struct ad7418_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- i2c_detach_client(client);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index ecbf69484bf..b11e06f644b 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -78,7 +78,6 @@ clearing it. Weird, ey? --Phil */
/* Each client has this additional data */
struct adm1021_data {
- struct i2c_client client;
struct device *hwmon_dev;
enum chips type;
@@ -98,23 +97,42 @@ struct adm1021_data {
u8 remote_temp_offset_prec;
};
-static int adm1021_attach_adapter(struct i2c_adapter *adapter);
-static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adm1021_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adm1021_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void adm1021_init_client(struct i2c_client *client);
-static int adm1021_detach_client(struct i2c_client *client);
+static int adm1021_remove(struct i2c_client *client);
static struct adm1021_data *adm1021_update_device(struct device *dev);
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
static int read_only;
+static const struct i2c_device_id adm1021_id[] = {
+ { "adm1021", adm1021 },
+ { "adm1023", adm1023 },
+ { "max1617", max1617 },
+ { "max1617a", max1617a },
+ { "thmc10", thmc10 },
+ { "lm84", lm84 },
+ { "gl523sm", gl523sm },
+ { "mc1066", mc1066 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1021_id);
+
/* This is the driver that will be inserted */
static struct i2c_driver adm1021_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1021",
},
- .attach_adapter = adm1021_attach_adapter,
- .detach_client = adm1021_detach_client,
+ .probe = adm1021_probe,
+ .remove = adm1021_remove,
+ .id_table = adm1021_id,
+ .detect = adm1021_detect,
+ .address_data = &addr_data,
};
static ssize_t show_temp(struct device *dev,
@@ -216,13 +234,6 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static int adm1021_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adm1021_detect);
-}
-
static struct attribute *adm1021_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
@@ -243,36 +254,21 @@ static const struct attribute_group adm1021_group = {
.attrs = adm1021_attributes,
};
-static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1021_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
+ struct i2c_adapter *adapter = client->adapter;
int i;
- struct i2c_client *client;
- struct adm1021_data *data;
- int err = 0;
const char *type_name = "";
int conv_rate, status, config;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("adm1021: detect failed, "
"smbus byte data not supported!\n");
- goto error0;
- }
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access adm1021 register values. */
-
- if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
- pr_debug("adm1021: detect failed, kzalloc failed!\n");
- err = -ENOMEM;
- goto error0;
+ return -ENODEV;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adm1021_driver;
status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
conv_rate = i2c_smbus_read_byte_data(client,
ADM1021_REG_CONV_RATE_R);
@@ -284,8 +280,7 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|| (conv_rate & 0xF8) != 0x00) {
pr_debug("adm1021: detect failed, "
"chip not detected!\n");
- err = -ENODEV;
- goto error1;
+ return -ENODEV;
}
}
@@ -336,24 +331,36 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
type_name = "mc1066";
}
pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
- type_name, i2c_adapter_id(adapter), address);
+ type_name, i2c_adapter_id(adapter), client->addr);
+ strlcpy(info->type, type_name, I2C_NAME_SIZE);
- /* Fill in the remaining client fields */
- strlcpy(client->name, type_name, I2C_NAME_SIZE);
- data->type = kind;
- mutex_init(&data->update_lock);
+ return 0;
+}
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto error1;
+static int adm1021_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adm1021_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL);
+ if (!data) {
+ pr_debug("adm1021: detect failed, kzalloc failed!\n");
+ err = -ENOMEM;
+ goto error0;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->type = id->driver_data;
+ mutex_init(&data->update_lock);
/* Initialize the ADM1021 chip */
- if (kind != lm84 && !read_only)
+ if (data->type != lm84 && !read_only)
adm1021_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
- goto error2;
+ goto error1;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -365,8 +372,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
error3:
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
-error2:
- i2c_detach_client(client);
error1:
kfree(data);
error0:
@@ -382,17 +387,13 @@ static void adm1021_init_client(struct i2c_client *client)
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
}
-static int adm1021_detach_client(struct i2c_client *client)
+static int adm1021_remove(struct i2c_client *client)
{
struct adm1021_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index 1d76de7d75c..4db04d603ec 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -2,7 +2,7 @@
* adm1025.c
*
* Copyright (C) 2000 Chen-Yuan Wu <gwu@esoft.com>
- * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
*
* The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
* voltages (including its own power source) and up to two temperatures
@@ -109,22 +109,35 @@ static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
* Functions declaration
*/
-static int adm1025_attach_adapter(struct i2c_adapter *adapter);
-static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adm1025_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adm1025_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void adm1025_init_client(struct i2c_client *client);
-static int adm1025_detach_client(struct i2c_client *client);
+static int adm1025_remove(struct i2c_client *client);
static struct adm1025_data *adm1025_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id adm1025_id[] = {
+ { "adm1025", adm1025 },
+ { "ne1619", ne1619 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1025_id);
+
static struct i2c_driver adm1025_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1025",
},
- .attach_adapter = adm1025_attach_adapter,
- .detach_client = adm1025_detach_client,
+ .probe = adm1025_probe,
+ .remove = adm1025_remove,
+ .id_table = adm1025_id,
+ .detect = adm1025_detect,
+ .address_data = &addr_data,
};
/*
@@ -132,7 +145,6 @@ static struct i2c_driver adm1025_driver = {
*/
struct adm1025_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -344,13 +356,6 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
* Real code
*/
-static int adm1025_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adm1025_detect);
-}
-
static struct attribute *adm1025_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
@@ -403,31 +408,16 @@ static const struct attribute_group adm1025_group_in4 = {
.attrs = adm1025_attributes_in4,
};
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1025_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct adm1025_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
const char *name = "";
u8 config;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adm1025_driver;
+ return -ENODEV;
/*
* Now we do the remaining detection. A negative kind means that
@@ -448,8 +438,8 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
ADM1025_REG_STATUS2) & 0xBC) != 0x00) {
dev_dbg(&adapter->dev,
"ADM1025 detection failed at 0x%02x.\n",
- address);
- goto exit_free;
+ client->addr);
+ return -ENODEV;
}
}
@@ -465,7 +455,7 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
}
} else
if (man_id == 0xA1) { /* Philips */
- if (address != 0x2E
+ if (client->addr != 0x2E
&& (chip_id & 0xF0) == 0x20) { /* NE1619 */
kind = ne1619;
}
@@ -475,7 +465,7 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
@@ -484,23 +474,36 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
} else if (kind == ne1619) {
name = "ne1619";
}
+ strlcpy(info->type, name, I2C_NAME_SIZE);
- /* We can fill in the remaining client fields */
- strlcpy(client->name, name, I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ return 0;
+}
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+static int adm1025_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adm1025_data *data;
+ int err;
+ u8 config;
+
+ data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
/* Initialize the ADM1025 chip */
adm1025_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group)))
- goto exit_detach;
+ goto exit_free;
/* Pin 11 is either in4 (+12V) or VID4 */
+ config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
if (!(config & 0x20)) {
if ((err = sysfs_create_group(&client->dev.kobj,
&adm1025_group_in4)))
@@ -518,8 +521,6 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -568,18 +569,14 @@ static void adm1025_init_client(struct i2c_client *client)
(reg&0x7E)|0x01);
}
-static int adm1025_detach_client(struct i2c_client *client)
+static int adm1025_remove(struct i2c_client *client)
{
struct adm1025_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 904c6ce9d83..7fe2441fc84 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -259,7 +259,6 @@ struct pwm_data {
};
struct adm1026_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
@@ -293,10 +292,11 @@ struct adm1026_data {
u8 config3; /* Register value */
};
-static int adm1026_attach_adapter(struct i2c_adapter *adapter);
-static int adm1026_detect(struct i2c_adapter *adapter, int address,
- int kind);
-static int adm1026_detach_client(struct i2c_client *client);
+static int adm1026_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adm1026_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int adm1026_remove(struct i2c_client *client);
static int adm1026_read_value(struct i2c_client *client, u8 reg);
static int adm1026_write_value(struct i2c_client *client, u8 reg, int value);
static void adm1026_print_gpio(struct i2c_client *client);
@@ -305,22 +305,24 @@ static struct adm1026_data *adm1026_update_device(struct device *dev);
static void adm1026_init_client(struct i2c_client *client);
+static const struct i2c_device_id adm1026_id[] = {
+ { "adm1026", adm1026 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1026_id);
+
static struct i2c_driver adm1026_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1026",
},
- .attach_adapter = adm1026_attach_adapter,
- .detach_client = adm1026_detach_client,
+ .probe = adm1026_probe,
+ .remove = adm1026_remove,
+ .id_table = adm1026_id,
+ .detect = adm1026_detect,
+ .address_data = &addr_data,
};
-static int adm1026_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON)) {
- return 0;
- }
- return i2c_probe(adapter, &addr_data, adm1026_detect);
-}
-
static int adm1026_read_value(struct i2c_client *client, u8 reg)
{
int res;
@@ -1647,48 +1649,32 @@ static const struct attribute_group adm1026_group_in8_9 = {
.attrs = adm1026_attributes_in8_9,
};
-static int adm1026_detect(struct i2c_adapter *adapter, int address,
- int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1026_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
+ struct i2c_adapter *adapter = client->adapter;
+ int address = client->addr;
int company, verstep;
- struct i2c_client *client;
- struct adm1026_data *data;
- int err = 0;
- const char *type_name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
/* We need to be able to do byte I/O */
- goto exit;
+ return -ENODEV;
};
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access adm1026_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adm1026_driver;
-
/* Now, we do the remaining detection. */
company = adm1026_read_value(client, ADM1026_REG_COMPANY);
verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
- dev_dbg(&client->dev, "Detecting device at %d,0x%02x with"
+ dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
i2c_adapter_id(client->adapter), client->addr,
company, verstep);
/* If auto-detecting, Determine the chip type. */
if (kind <= 0) {
- dev_dbg(&client->dev, "Autodetecting device at %d,0x%02x "
+ dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x "
"...\n", i2c_adapter_id(adapter), address);
if (company == ADM1026_COMPANY_ANALOG_DEV
&& verstep == ADM1026_VERSTEP_ADM1026) {
@@ -1704,7 +1690,7 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
verstep);
kind = any_chip;
} else {
- dev_dbg(&client->dev, ": Autodetection "
+ dev_dbg(&adapter->dev, ": Autodetection "
"failed\n");
/* Not an ADM1026 ... */
if (kind == 0) { /* User used force=x,y */
@@ -1713,33 +1699,29 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
"force_adm1026.\n",
i2c_adapter_id(adapter), address);
}
- goto exitfree;
+ return -ENODEV;
}
}
+ strlcpy(info->type, "adm1026", I2C_NAME_SIZE);
- /* Fill in the chip specific driver values */
- switch (kind) {
- case any_chip :
- type_name = "adm1026";
- break;
- case adm1026 :
- type_name = "adm1026";
- break;
- default :
- dev_err(&adapter->dev, ": Internal error, invalid "
- "kind (%d)!\n", kind);
- err = -EFAULT;
- goto exitfree;
+ return 0;
+}
+
+static int adm1026_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adm1026_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
}
- strlcpy(client->name, type_name, I2C_NAME_SIZE);
- /* Fill in the remaining client fields */
+ i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exitfree;
-
/* Set the VRM version */
data->vrm = vid_which_vrm();
@@ -1748,7 +1730,7 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group)))
- goto exitdetach;
+ goto exitfree;
if (data->config1 & CFG1_AIN8_9)
err = sysfs_create_group(&client->dev.kobj,
&adm1026_group_in8_9);
@@ -1773,15 +1755,13 @@ exitremove:
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
else
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
-exitdetach:
- i2c_detach_client(client);
exitfree:
kfree(data);
exit:
return err;
}
-static int adm1026_detach_client(struct i2c_client *client)
+static int adm1026_remove(struct i2c_client *client)
{
struct adm1026_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
@@ -1790,7 +1770,6 @@ static int adm1026_detach_client(struct i2c_client *client)
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
else
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
- i2c_detach_client(client);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 2c6608d453c..ba84ca5923f 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -115,9 +115,11 @@ static const u8 ADM1029_REG_FAN_DIV[] = {
* Functions declaration
*/
-static int adm1029_attach_adapter(struct i2c_adapter *adapter);
-static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind);
-static int adm1029_detach_client(struct i2c_client *client);
+static int adm1029_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adm1029_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int adm1029_remove(struct i2c_client *client);
static struct adm1029_data *adm1029_update_device(struct device *dev);
static int adm1029_init_client(struct i2c_client *client);
@@ -125,12 +127,22 @@ static int adm1029_init_client(struct i2c_client *client);
* Driver data (common to all clients)
*/
+static const struct i2c_device_id adm1029_id[] = {
+ { "adm1029", adm1029 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1029_id);
+
static struct i2c_driver adm1029_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1029",
},
- .attach_adapter = adm1029_attach_adapter,
- .detach_client = adm1029_detach_client,
+ .probe = adm1029_probe,
+ .remove = adm1029_remove,
+ .id_table = adm1029_id,
+ .detect = adm1029_detect,
+ .address_data = &addr_data,
};
/*
@@ -138,7 +150,6 @@ static struct i2c_driver adm1029_driver = {
*/
struct adm1029_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -284,37 +295,14 @@ static const struct attribute_group adm1029_group = {
* Real code
*/
-static int adm1029_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1029_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adm1029_detect);
-}
+ struct i2c_adapter *adapter = client->adapter;
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-
-static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *client;
- struct adm1029_data *data;
- int err = 0;
- const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adm1029_driver;
+ return -ENODEV;
/* Now we do the detection and identification. A negative kind
* means that the driver was loaded with no force parameter
@@ -362,32 +350,41 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind <= 0) { /* identification failed */
pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X)\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
+ strlcpy(info->type, "adm1029", I2C_NAME_SIZE);
- if (kind == adm1029) {
- name = "adm1029";
+ return 0;
+}
+
+static int adm1029_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adm1029_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
}
- /* We can fill in the remaining client fields */
- strlcpy(client->name, name, I2C_NAME_SIZE);
+ i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
/*
* Initialize the ADM1029 chip
* Check config register
*/
- if (adm1029_init_client(client) == 0)
- goto exit_detach;
+ if (adm1029_init_client(client) == 0) {
+ err = -ENODEV;
+ goto exit_free;
+ }
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -399,8 +396,6 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -424,17 +419,13 @@ static int adm1029_init_client(struct i2c_client *client)
return 1;
}
-static int adm1029_detach_client(struct i2c_client *client)
+static int adm1029_remove(struct i2c_client *client)
{
struct adm1029_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 2bffcab7dc9..789441830cd 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -70,7 +70,6 @@ typedef u8 auto_chan_table_t[8][2];
/* Each client has this additional data */
struct adm1031_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
int chip_type;
@@ -99,19 +98,32 @@ struct adm1031_data {
s8 temp_crit[3];
};
-static int adm1031_attach_adapter(struct i2c_adapter *adapter);
-static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adm1031_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adm1031_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void adm1031_init_client(struct i2c_client *client);
-static int adm1031_detach_client(struct i2c_client *client);
+static int adm1031_remove(struct i2c_client *client);
static struct adm1031_data *adm1031_update_device(struct device *dev);
+static const struct i2c_device_id adm1031_id[] = {
+ { "adm1030", adm1030 },
+ { "adm1031", adm1031 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1031_id);
+
/* This is the driver that will be inserted */
static struct i2c_driver adm1031_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1031",
},
- .attach_adapter = adm1031_attach_adapter,
- .detach_client = adm1031_detach_client,
+ .probe = adm1031_probe,
+ .remove = adm1031_remove,
+ .id_table = adm1031_id,
+ .detect = adm1031_detect,
+ .address_data = &addr_data,
};
static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
@@ -693,13 +705,6 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
-static int adm1031_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adm1031_detect);
-}
-
static struct attribute *adm1031_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
@@ -770,27 +775,15 @@ static const struct attribute_group adm1031_group_opt = {
.attrs = adm1031_attributes_opt,
};
-/* This function is called by i2c_probe */
-static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm1031_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct adm1031_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adm1031_driver;
+ return -ENODEV;
if (kind < 0) {
int id, co;
@@ -798,7 +791,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
co = i2c_smbus_read_byte_data(client, 0x3e);
if (!((id == 0x31 || id == 0x30) && co == 0x41))
- goto exit_free;
+ return -ENODEV;
kind = (id == 0x30) ? adm1030 : adm1031;
}
@@ -809,28 +802,43 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
* auto fan control helper table. */
if (kind == adm1030) {
name = "adm1030";
- data->chan_select_table = &auto_channel_select_table_adm1030;
} else if (kind == adm1031) {
name = "adm1031";
- data->chan_select_table = &auto_channel_select_table_adm1031;
}
- data->chip_type = kind;
+ strlcpy(info->type, name, I2C_NAME_SIZE);
- strlcpy(client->name, name, I2C_NAME_SIZE);
+ return 0;
+}
+
+static int adm1031_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adm1031_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->chip_type = id->driver_data;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ if (data->chip_type == adm1030)
+ data->chan_select_table = &auto_channel_select_table_adm1030;
+ else
+ data->chan_select_table = &auto_channel_select_table_adm1031;
/* Initialize the ADM1031 chip */
adm1031_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group)))
- goto exit_detach;
+ goto exit_free;
- if (kind == adm1031) {
+ if (data->chip_type == adm1031) {
if ((err = sysfs_create_group(&client->dev.kobj,
&adm1031_group_opt)))
goto exit_remove;
@@ -847,25 +855,19 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int adm1031_detach_client(struct i2c_client *client)
+static int adm1031_remove(struct i2c_client *client)
{
struct adm1031_data *data = i2c_get_clientdata(client);
- int ret;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
- if ((ret = i2c_detach_client(client)) != 0) {
- return ret;
- }
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 149ef25252e..2444b15f2e9 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -130,25 +130,37 @@ static inline unsigned int AOUT_FROM_REG(u8 reg)
return SCALE(reg, 1250, 255);
}
-static int adm9240_attach_adapter(struct i2c_adapter *adapter);
-static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adm9240_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adm9240_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void adm9240_init_client(struct i2c_client *client);
-static int adm9240_detach_client(struct i2c_client *client);
+static int adm9240_remove(struct i2c_client *client);
static struct adm9240_data *adm9240_update_device(struct device *dev);
/* driver data */
+static const struct i2c_device_id adm9240_id[] = {
+ { "adm9240", adm9240 },
+ { "ds1780", ds1780 },
+ { "lm81", lm81 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm9240_id);
+
static struct i2c_driver adm9240_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adm9240",
},
- .attach_adapter = adm9240_attach_adapter,
- .detach_client = adm9240_detach_client,
+ .probe = adm9240_probe,
+ .remove = adm9240_remove,
+ .id_table = adm9240_id,
+ .detect = adm9240_detect,
+ .address_data = &addr_data,
};
/* per client data */
struct adm9240_data {
- enum chips type;
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid;
@@ -532,28 +544,17 @@ static const struct attribute_group adm9240_group = {
/*** sensor chip detect and driver install ***/
-static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adm9240_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct adm9240_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
const char *name = "";
+ int address = new_client->addr;
u8 man_id, die_rev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &adm9240_driver;
- new_client->flags = 0;
+ return -ENODEV;
if (kind == 0) {
kind = adm9240;
@@ -566,7 +567,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
!= address) {
dev_err(&adapter->dev, "detect fail: address match, "
"0x%02x\n", address);
- goto exit_free;
+ return -ENODEV;
}
/* check known chip manufacturer */
@@ -581,7 +582,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
} else {
dev_err(&adapter->dev, "detect fail: unknown manuf, "
"0x%02x\n", man_id);
- goto exit_free;
+ return -ENODEV;
}
/* successful detect, print chip info */
@@ -600,20 +601,31 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
} else if (kind == lm81) {
name = "lm81";
}
+ strlcpy(info->type, name, I2C_NAME_SIZE);
- /* fill in the remaining client fields and attach */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
- data->type = kind;
- mutex_init(&data->update_lock);
+ return 0;
+}
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
+static int adm9240_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct adm9240_data *data;
+ int err;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
+ mutex_init(&data->update_lock);
adm9240_init_client(new_client);
/* populate sysfs filesystem */
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -625,32 +637,19 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
-static int adm9240_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adm9240_detect);
-}
-
-static int adm9240_detach_client(struct i2c_client *client)
+static int adm9240_remove(struct i2c_client *client)
{
struct adm9240_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 5c8b6e0ff47..5c39b4af1b2 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -64,7 +64,6 @@ static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
/* Each client has this additional data */
struct ads7828_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock; /* mutex protect updates */
char valid; /* !=0 if following fields are valid */
@@ -73,7 +72,10 @@ struct ads7828_data {
};
/* Function declaration - necessary due to function dependencies */
-static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ads7828_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int ads7828_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
/* The ADS7828 returns the 12-bit sample in two bytes,
these are read as a word then byte-swapped */
@@ -156,58 +158,43 @@ static const struct attribute_group ads7828_group = {
.attrs = ads7828_attributes,
};
-static int ads7828_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, ads7828_detect);
-}
-
-static int ads7828_detach_client(struct i2c_client *client)
+static int ads7828_remove(struct i2c_client *client)
{
struct ads7828_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
- i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
return 0;
}
+static const struct i2c_device_id ads7828_id[] = {
+ { "ads7828", ads7828 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ads7828_id);
+
/* This is the driver that will be inserted */
static struct i2c_driver ads7828_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "ads7828",
},
- .attach_adapter = ads7828_attach_adapter,
- .detach_client = ads7828_detach_client,
+ .probe = ads7828_probe,
+ .remove = ads7828_remove,
+ .id_table = ads7828_id,
+ .detect = ads7828_detect,
+ .address_data = &addr_data,
};
-/* This function is called by i2c_probe */
-static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int ads7828_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct ads7828_data *data;
- int err = 0;
- const char *name = "";
+ struct i2c_adapter *adapter = client->adapter;
/* Check we have a valid client */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access ads7828_read_value. */
- data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &ads7828_driver;
+ return -ENODEV;
/* Now, we do the remaining detection. There is no identification
dedicated register so attempt to sanity check using knowledge of
@@ -225,32 +212,34 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
printk(KERN_DEBUG
"%s : Doesn't look like an ads7828 device\n",
__func__);
- goto exit_free;
+ return -ENODEV;
}
}
}
+ strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
- /* Determine the chip type - only one kind supported! */
- if (kind <= 0)
- kind = ads7828;
+ return 0;
+}
- if (kind == ads7828)
- name = "ads7828";
+static int ads7828_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ads7828_data *data;
+ int err;
- /* Fill in the remaining client fields, put it into the global list */
- strlcpy(client->name, name, I2C_NAME_SIZE);
+ data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- err = i2c_attach_client(client);
- if (err)
- goto exit_free;
-
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
if (err)
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -262,8 +251,6 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 6b5325f33a2..d368d8f845e 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -138,7 +138,6 @@ I2C_CLIENT_INSMOD_1(adt7470);
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
struct adt7470_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct attribute_group attrs;
struct mutex lock;
@@ -164,16 +163,28 @@ struct adt7470_data {
u8 pwm_auto_temp[ADT7470_PWM_COUNT];
};
-static int adt7470_attach_adapter(struct i2c_adapter *adapter);
-static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind);
-static int adt7470_detach_client(struct i2c_client *client);
+static int adt7470_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adt7470_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int adt7470_remove(struct i2c_client *client);
+
+static const struct i2c_device_id adt7470_id[] = {
+ { "adt7470", adt7470 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adt7470_id);
static struct i2c_driver adt7470_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adt7470",
},
- .attach_adapter = adt7470_attach_adapter,
- .detach_client = adt7470_detach_client,
+ .probe = adt7470_probe,
+ .remove = adt7470_remove,
+ .id_table = adt7470_id,
+ .detect = adt7470_detect,
+ .address_data = &addr_data,
};
/*
@@ -1004,64 +1015,52 @@ static struct attribute *adt7470_attr[] =
NULL
};
-static int adt7470_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adt7470_detect);
-}
-
-static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adt7470_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct adt7470_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adt7470_driver;
-
- i2c_set_clientdata(client, data);
-
- mutex_init(&data->lock);
+ return -ENODEV;
if (kind <= 0) {
int vendor, device, revision;
vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
- if (vendor != ADT7470_VENDOR) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (vendor != ADT7470_VENDOR)
+ return -ENODEV;
device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
- if (device != ADT7470_DEVICE) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (device != ADT7470_DEVICE)
+ return -ENODEV;
revision = i2c_smbus_read_byte_data(client,
ADT7470_REG_REVISION);
- if (revision != ADT7470_REVISION) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (revision != ADT7470_REVISION)
+ return -ENODEV;
} else
dev_dbg(&adapter->dev, "detection forced\n");
- strlcpy(client->name, "adt7470", I2C_NAME_SIZE);
+ strlcpy(info->type, "adt7470", I2C_NAME_SIZE);
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ return 0;
+}
+
+static int adt7470_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7470_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->lock);
dev_info(&client->dev, "%s chip found\n", client->name);
@@ -1071,7 +1070,7 @@ static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
data->attrs.attrs = adt7470_attr;
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -1083,21 +1082,18 @@ static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int adt7470_detach_client(struct i2c_client *client)
+static int adt7470_remove(struct i2c_client *client)
{
struct adt7470_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- i2c_detach_client(client);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index 93dbf5e7ff8..ce4a7cb5a11 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -143,7 +143,6 @@ I2C_CLIENT_INSMOD_1(adt7473);
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
struct adt7473_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct attribute_group attrs;
struct mutex lock;
@@ -178,16 +177,28 @@ struct adt7473_data {
u8 max_duty_at_overheat;
};
-static int adt7473_attach_adapter(struct i2c_adapter *adapter);
-static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind);
-static int adt7473_detach_client(struct i2c_client *client);
+static int adt7473_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adt7473_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int adt7473_remove(struct i2c_client *client);
+
+static const struct i2c_device_id adt7473_id[] = {
+ { "adt7473", adt7473 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adt7473_id);
static struct i2c_driver adt7473_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "adt7473",
},
- .attach_adapter = adt7473_attach_adapter,
- .detach_client = adt7473_detach_client,
+ .probe = adt7473_probe,
+ .remove = adt7473_remove,
+ .id_table = adt7473_id,
+ .detect = adt7473_detect,
+ .address_data = &addr_data,
};
/*
@@ -1042,66 +1053,52 @@ static struct attribute *adt7473_attr[] =
NULL
};
-static int adt7473_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int adt7473_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, adt7473_detect);
-}
-
-static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *client;
- struct adt7473_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- data = kzalloc(sizeof(struct adt7473_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &adt7473_driver;
-
- i2c_set_clientdata(client, data);
-
- mutex_init(&data->lock);
+ return -ENODEV;
if (kind <= 0) {
int vendor, device, revision;
vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
- if (vendor != ADT7473_VENDOR) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (vendor != ADT7473_VENDOR)
+ return -ENODEV;
device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
- if (device != ADT7473_DEVICE) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (device != ADT7473_DEVICE)
+ return -ENODEV;
revision = i2c_smbus_read_byte_data(client,
ADT7473_REG_REVISION);
- if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69) {
- err = -ENODEV;
- goto exit_free;
- }
+ if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69)
+ return -ENODEV;
} else
dev_dbg(&adapter->dev, "detection forced\n");
- strlcpy(client->name, "adt7473", I2C_NAME_SIZE);
+ strlcpy(info->type, "adt7473", I2C_NAME_SIZE);
- err = i2c_attach_client(client);
- if (err)
- goto exit_free;
+ return 0;
+}
+
+static int adt7473_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7473_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct adt7473_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->lock);
dev_info(&client->dev, "%s chip found\n", client->name);
@@ -1112,7 +1109,7 @@ static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
data->attrs.attrs = adt7473_attr;
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
if (err)
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -1124,21 +1121,18 @@ static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int adt7473_detach_client(struct i2c_client *client)
+static int adt7473_remove(struct i2c_client *client)
{
struct adt7473_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- i2c_detach_client(client);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index fe2eea4d799..8a45a2e6ba8 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -176,10 +176,8 @@ static u8 DIV_TO_REG(long val)
data is pointed to by client->data. The structure itself is
dynamically allocated, at the same time the client itself is allocated. */
struct asb100_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex lock;
- enum chips type;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
@@ -206,18 +204,30 @@ struct asb100_data {
static int asb100_read_value(struct i2c_client *client, u16 reg);
static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
-static int asb100_attach_adapter(struct i2c_adapter *adapter);
-static int asb100_detect(struct i2c_adapter *adapter, int address, int kind);
-static int asb100_detach_client(struct i2c_client *client);
+static int asb100_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int asb100_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int asb100_remove(struct i2c_client *client);
static struct asb100_data *asb100_update_device(struct device *dev);
static void asb100_init_client(struct i2c_client *client);
+static const struct i2c_device_id asb100_id[] = {
+ { "asb100", asb100 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, asb100_id);
+
static struct i2c_driver asb100_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "asb100",
},
- .attach_adapter = asb100_attach_adapter,
- .detach_client = asb100_detach_client,
+ .probe = asb100_probe,
+ .remove = asb100_remove,
+ .id_table = asb100_id,
+ .detect = asb100_detect,
+ .address_data = &addr_data,
};
/* 7 Voltages */
@@ -619,35 +629,13 @@ static const struct attribute_group asb100_group = {
.attrs = asb100_attributes,
};
-/* This function is called when:
- asb100_driver is inserted (when this module is loaded), for each
- available adapter
- when a new adapter is inserted (and asb100_driver is still present)
- */
-static int asb100_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, asb100_detect);
-}
-
-static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
- int kind, struct i2c_client *client)
+static int asb100_detect_subclients(struct i2c_client *client)
{
int i, id, err;
+ int address = client->addr;
+ unsigned short sc_addr[2];
struct asb100_data *data = i2c_get_clientdata(client);
-
- data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!(data->lm75[0])) {
- err = -ENOMEM;
- goto ERROR_SC_0;
- }
-
- data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!(data->lm75[1])) {
- err = -ENOMEM;
- goto ERROR_SC_1;
- }
+ struct i2c_adapter *adapter = client->adapter;
id = i2c_adapter_id(adapter);
@@ -665,37 +653,34 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
(force_subclients[2] & 0x07) |
((force_subclients[3] & 0x07) << 4));
- data->lm75[0]->addr = force_subclients[2];
- data->lm75[1]->addr = force_subclients[3];
+ sc_addr[0] = force_subclients[2];
+ sc_addr[1] = force_subclients[3];
} else {
int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
- data->lm75[0]->addr = 0x48 + (val & 0x07);
- data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07);
+ sc_addr[0] = 0x48 + (val & 0x07);
+ sc_addr[1] = 0x48 + ((val >> 4) & 0x07);
}
- if (data->lm75[0]->addr == data->lm75[1]->addr) {
+ if (sc_addr[0] == sc_addr[1]) {
dev_err(&client->dev, "duplicate addresses 0x%x "
- "for subclients\n", data->lm75[0]->addr);
+ "for subclients\n", sc_addr[0]);
err = -ENODEV;
goto ERROR_SC_2;
}
- for (i = 0; i <= 1; i++) {
- i2c_set_clientdata(data->lm75[i], NULL);
- data->lm75[i]->adapter = adapter;
- data->lm75[i]->driver = &asb100_driver;
- strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE);
- }
-
- if ((err = i2c_attach_client(data->lm75[0]))) {
+ data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
+ if (!data->lm75[0]) {
dev_err(&client->dev, "subclient %d registration "
- "at address 0x%x failed.\n", i, data->lm75[0]->addr);
+ "at address 0x%x failed.\n", 1, sc_addr[0]);
+ err = -ENOMEM;
goto ERROR_SC_2;
}
- if ((err = i2c_attach_client(data->lm75[1]))) {
+ data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
+ if (!data->lm75[1]) {
dev_err(&client->dev, "subclient %d registration "
- "at address 0x%x failed.\n", i, data->lm75[1]->addr);
+ "at address 0x%x failed.\n", 2, sc_addr[1]);
+ err = -ENOMEM;
goto ERROR_SC_3;
}
@@ -703,55 +688,31 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
/* Undo inits in case of errors */
ERROR_SC_3:
- i2c_detach_client(data->lm75[0]);
+ i2c_unregister_device(data->lm75[0]);
ERROR_SC_2:
- kfree(data->lm75[1]);
-ERROR_SC_1:
- kfree(data->lm75[0]);
-ERROR_SC_0:
return err;
}
-static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int asb100_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- int err;
- struct i2c_client *client;
- struct asb100_data *data;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("asb100.o: detect failed, "
"smbus byte data not supported!\n");
- err = -ENODEV;
- goto ERROR0;
+ return -ENODEV;
}
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access asb100_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL))) {
- pr_debug("asb100.o: detect failed, kzalloc failed!\n");
- err = -ENOMEM;
- goto ERROR0;
- }
-
- client = &data->client;
- mutex_init(&data->lock);
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &asb100_driver;
-
- /* Now, we do the remaining detection. */
-
/* The chip may be stuck in some other bank than bank 0. This may
make reading other information impossible. Specify a force=... or
force_*=... parameter, and the chip will be reset to the right
bank. */
if (kind < 0) {
- int val1 = asb100_read_value(client, ASB100_REG_BANK);
- int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN);
+ int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
+ int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
/* If we're in bank 0 */
if ((!(val1 & 0x07)) &&
@@ -761,48 +722,60 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
((val1 & 0x80) && (val2 != 0x06)))) {
pr_debug("asb100.o: detect failed, "
"bad chip id 0x%02x!\n", val2);
- err = -ENODEV;
- goto ERROR1;
+ return -ENODEV;
}
} /* kind < 0 */
/* We have either had a force parameter, or we have already detected
Winbond. Put it now into bank 0 and Vendor ID High Byte */
- asb100_write_value(client, ASB100_REG_BANK,
- (asb100_read_value(client, ASB100_REG_BANK) & 0x78) | 0x80);
+ i2c_smbus_write_byte_data(client, ASB100_REG_BANK,
+ (i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78)
+ | 0x80);
/* Determine the chip type. */
if (kind <= 0) {
- int val1 = asb100_read_value(client, ASB100_REG_WCHIPID);
- int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN);
+ int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
+ int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
if ((val1 == 0x31) && (val2 == 0x06))
kind = asb100;
else {
if (kind == 0)
- dev_warn(&client->dev, "ignoring "
+ dev_warn(&adapter->dev, "ignoring "
"'force' parameter for unknown chip "
"at adapter %d, address 0x%02x.\n",
- i2c_adapter_id(adapter), address);
- err = -ENODEV;
- goto ERROR1;
+ i2c_adapter_id(adapter), client->addr);
+ return -ENODEV;
}
}
- /* Fill in remaining client fields and put it into the global list */
- strlcpy(client->name, "asb100", I2C_NAME_SIZE);
- data->type = kind;
- mutex_init(&data->update_lock);
+ strlcpy(info->type, "asb100", I2C_NAME_SIZE);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto ERROR1;
+ return 0;
+}
+
+static int asb100_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err;
+ struct asb100_data *data;
+
+ data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
+ if (!data) {
+ pr_debug("asb100.o: probe failed, kzalloc failed!\n");
+ err = -ENOMEM;
+ goto ERROR0;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->lock);
+ mutex_init(&data->update_lock);
/* Attach secondary lm75 clients */
- if ((err = asb100_detect_subclients(adapter, address, kind,
- client)))
- goto ERROR2;
+ err = asb100_detect_subclients(client);
+ if (err)
+ goto ERROR1;
/* Initialize the chip */
asb100_init_client(client);
@@ -827,39 +800,25 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
ERROR4:
sysfs_remove_group(&client->dev.kobj, &asb100_group);
ERROR3:
- i2c_detach_client(data->lm75[1]);
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[1]);
- kfree(data->lm75[0]);
-ERROR2:
- i2c_detach_client(client);
+ i2c_unregister_device(data->lm75[1]);
+ i2c_unregister_device(data->lm75[0]);
ERROR1:
kfree(data);
ERROR0:
return err;
}
-static int asb100_detach_client(struct i2c_client *client)
+static int asb100_remove(struct i2c_client *client)
{
struct asb100_data *data = i2c_get_clientdata(client);
- int err;
-
- /* main client */
- if (data) {
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &asb100_group);
- }
- if ((err = i2c_detach_client(client)))
- return err;
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &asb100_group);
- /* main client */
- if (data)
- kfree(data);
+ i2c_unregister_device(data->lm75[1]);
+ i2c_unregister_device(data->lm75[0]);
- /* subclient */
- else
- kfree(client);
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 01c17e387f0..d191118ba0c 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -46,21 +46,32 @@ static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(atxp1);
-static int atxp1_attach_adapter(struct i2c_adapter * adapter);
-static int atxp1_detach_client(struct i2c_client * client);
+static int atxp1_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int atxp1_remove(struct i2c_client *client);
static struct atxp1_data * atxp1_update_device(struct device *dev);
-static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind);
+static int atxp1_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+
+static const struct i2c_device_id atxp1_id[] = {
+ { "atxp1", atxp1 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, atxp1_id);
static struct i2c_driver atxp1_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "atxp1",
},
- .attach_adapter = atxp1_attach_adapter,
- .detach_client = atxp1_detach_client,
+ .probe = atxp1_probe,
+ .remove = atxp1_remove,
+ .id_table = atxp1_id,
+ .detect = atxp1_detect,
+ .address_data = &addr_data,
};
struct atxp1_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated;
@@ -263,35 +274,16 @@ static const struct attribute_group atxp1_group = {
};
-static int atxp1_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int atxp1_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, &atxp1_detect);
-};
+ struct i2c_adapter *adapter = new_client->adapter;
-static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client * new_client;
- struct atxp1_data * data;
- int err = 0;
u8 temp;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
-
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &atxp1_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* Detect ATXP1, checking if vendor ID registers are all zero */
if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
@@ -305,35 +297,46 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
(i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
- goto exit_free;
+ return -ENODEV;
}
/* Get VRM */
- data->vrm = vid_which_vrm();
+ temp = vid_which_vrm();
- if ((data->vrm != 90) && (data->vrm != 91)) {
- dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
- data->vrm / 10, data->vrm % 10);
- goto exit_free;
+ if ((temp != 90) && (temp != 91)) {
+ dev_err(&adapter->dev, "atxp1: Not supporting VRM %d.%d\n",
+ temp / 10, temp % 10);
+ return -ENODEV;
}
- strncpy(new_client->name, "atxp1", I2C_NAME_SIZE);
-
- data->valid = 0;
+ strlcpy(info->type, "atxp1", I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ return 0;
+}
- err = i2c_attach_client(new_client);
+static int atxp1_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct atxp1_data *data;
+ int err;
- if (err)
- {
- dev_err(&new_client->dev, "Attach client error.\n");
- goto exit_free;
+ data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
}
+ /* Get VRM */
+ data->vrm = vid_which_vrm();
+
+ i2c_set_clientdata(new_client, data);
+ data->valid = 0;
+
+ mutex_init(&data->update_lock);
+
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -348,30 +351,22 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
};
-static int atxp1_detach_client(struct i2c_client * client)
+static int atxp1_remove(struct i2c_client *client)
{
struct atxp1_data * data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
- err = i2c_detach_client(client);
-
- if (err)
- dev_err(&client->dev, "Failed to detach client.\n");
- else
- kfree(data);
+ kfree(data);
- return err;
+ return 0;
};
static int __init atxp1_init(void)
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 5f300ffed65..7415381601c 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -72,7 +72,6 @@ static const u8 DS1621_REG_TEMP[3] = {
/* Each client has this additional data */
struct ds1621_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -82,20 +81,32 @@ struct ds1621_data {
u8 conf; /* Register encoding, combined */
};
-static int ds1621_attach_adapter(struct i2c_adapter *adapter);
-static int ds1621_detect(struct i2c_adapter *adapter, int address,
- int kind);
+static int ds1621_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int ds1621_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void ds1621_init_client(struct i2c_client *client);
-static int ds1621_detach_client(struct i2c_client *client);
+static int ds1621_remove(struct i2c_client *client);
static struct ds1621_data *ds1621_update_client(struct device *dev);
+static const struct i2c_device_id ds1621_id[] = {
+ { "ds1621", ds1621 },
+ { "ds1625", ds1621 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1621_id);
+
/* This is the driver that will be inserted */
static struct i2c_driver ds1621_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "ds1621",
},
- .attach_adapter = ds1621_attach_adapter,
- .detach_client = ds1621_detach_client,
+ .probe = ds1621_probe,
+ .remove = ds1621_remove,
+ .id_table = ds1621_id,
+ .detect = ds1621_detect,
+ .address_data = &addr_data,
};
/* All registers are word-sized, except for the configuration register.
@@ -199,40 +210,18 @@ static const struct attribute_group ds1621_group = {
};
-static int ds1621_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, ds1621_detect);
-}
-
-/* This function is called by i2c_probe */
-static int ds1621_detect(struct i2c_adapter *adapter, int address,
- int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int ds1621_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
+ struct i2c_adapter *adapter = client->adapter;
int conf, temp;
- struct i2c_client *client;
- struct ds1621_data *data;
- int i, err = 0;
+ int i;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA
| I2C_FUNC_SMBUS_WRITE_BYTE))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access ds1621_{read,write}_value. */
- if (!(data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &ds1621_driver;
+ return -ENODEV;
/* Now, we do the remaining detection. It is lousy. */
if (kind < 0) {
@@ -241,29 +230,41 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
improbable in our case. */
conf = ds1621_read_value(client, DS1621_REG_CONF);
if (conf & DS1621_REG_CONFIG_NVB)
- goto exit_free;
+ return -ENODEV;
/* The 7 lowest bits of a temperature should always be 0. */
- for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
if (temp & 0x007f)
- goto exit_free;
+ return -ENODEV;
}
}
- /* Fill in remaining client fields and put it into the global list */
- strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ strlcpy(info->type, "ds1621", I2C_NAME_SIZE);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ return 0;
+}
+
+static int ds1621_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ds1621_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
/* Initialize the DS1621 chip */
ds1621_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -275,25 +276,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
- exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int ds1621_detach_client(struct i2c_client *client)
+static int ds1621_remove(struct i2c_client *client)
{
struct ds1621_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index dc1f30e432e..1692de36996 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -87,7 +87,6 @@ I2C_CLIENT_INSMOD_2(f75373, f75375);
struct f75375_data {
unsigned short addr;
- struct i2c_client *client;
struct device *hwmon_dev;
const char *name;
@@ -114,21 +113,12 @@ struct f75375_data {
s8 temp_max_hyst[2];
};
-static int f75375_attach_adapter(struct i2c_adapter *adapter);
-static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
-static int f75375_detach_client(struct i2c_client *client);
+static int f75375_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static int f75375_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int f75375_remove(struct i2c_client *client);
-static struct i2c_driver f75375_legacy_driver = {
- .driver = {
- .name = "f75375_legacy",
- },
- .attach_adapter = f75375_attach_adapter,
- .detach_client = f75375_detach_client,
-};
-
static const struct i2c_device_id f75375_id[] = {
{ "f75373", f75373 },
{ "f75375", f75375 },
@@ -137,12 +127,15 @@ static const struct i2c_device_id f75375_id[] = {
MODULE_DEVICE_TABLE(i2c, f75375_id);
static struct i2c_driver f75375_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "f75375",
},
.probe = f75375_probe,
.remove = f75375_remove,
.id_table = f75375_id,
+ .detect = f75375_detect,
+ .address_data = &addr_data,
};
static inline int f75375_read8(struct i2c_client *client, u8 reg)
@@ -607,22 +600,6 @@ static const struct attribute_group f75375_group = {
.attrs = f75375_attributes,
};
-static int f75375_detach_client(struct i2c_client *client)
-{
- int err;
-
- f75375_remove(client);
- err = i2c_detach_client(client);
- if (err) {
- dev_err(&client->dev,
- "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
- kfree(client);
- return 0;
-}
-
static void f75375_init(struct i2c_client *client, struct f75375_data *data,
struct f75375s_platform_data *f75375s_pdata)
{
@@ -651,7 +628,6 @@ static int f75375_probe(struct i2c_client *client,
return -ENOMEM;
i2c_set_clientdata(client, data);
- data->client = client;
mutex_init(&data->update_lock);
data->kind = id->driver_data;
@@ -700,29 +676,13 @@ static int f75375_remove(struct i2c_client *client)
return 0;
}
-static int f75375_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, f75375_detect);
-}
-
-/* This function is called by i2c_probe */
-static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int f75375_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
+ struct i2c_adapter *adapter = client->adapter;
u8 version = 0;
- int err = 0;
const char *name = "";
- struct i2c_device_id id;
-
- if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
- client->addr = address;
- client->adapter = adapter;
- client->driver = &f75375_legacy_driver;
if (kind < 0) {
u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
@@ -736,7 +696,7 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
dev_err(&adapter->dev,
"failed,%02X,%02X,%02X\n",
chipid, version, vendid);
- goto exit_free;
+ return -ENODEV;
}
}
@@ -746,43 +706,18 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
name = "f75373";
}
dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
- strlcpy(client->name, name, I2C_NAME_SIZE);
-
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
- strlcpy(id.name, name, I2C_NAME_SIZE);
- id.driver_data = kind;
- if ((err = f75375_probe(client, &id)) < 0)
- goto exit_detach;
+ strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
-
-exit_detach:
- i2c_detach_client(client);
-exit_free:
- kfree(client);
-exit:
- return err;
}
static int __init sensors_f75375_init(void)
{
- int status;
- status = i2c_add_driver(&f75375_driver);
- if (status)
- return status;
-
- status = i2c_add_driver(&f75375_legacy_driver);
- if (status)
- i2c_del_driver(&f75375_driver);
-
- return status;
+ return i2c_add_driver(&f75375_driver);
}
static void __exit sensors_f75375_exit(void)
{
- i2c_del_driver(&f75375_legacy_driver);
i2c_del_driver(&f75375_driver);
}
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index ed26b66e083..12c70e402cb 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -106,9 +106,11 @@ I2C_CLIENT_INSMOD_1(fscher);
* Functions declaration
*/
-static int fscher_attach_adapter(struct i2c_adapter *adapter);
-static int fscher_detect(struct i2c_adapter *adapter, int address, int kind);
-static int fscher_detach_client(struct i2c_client *client);
+static int fscher_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int fscher_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int fscher_remove(struct i2c_client *client);
static struct fscher_data *fscher_update_device(struct device *dev);
static void fscher_init_client(struct i2c_client *client);
@@ -119,12 +121,21 @@ static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value);
* Driver data (common to all clients)
*/
+static const struct i2c_device_id fscher_id[] = {
+ { "fscher", fscher },
+ { }
+};
+
static struct i2c_driver fscher_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "fscher",
},
- .attach_adapter = fscher_attach_adapter,
- .detach_client = fscher_detach_client,
+ .probe = fscher_probe,
+ .remove = fscher_remove,
+ .id_table = fscher_id,
+ .detect = fscher_detect,
+ .address_data = &addr_data,
};
/*
@@ -132,7 +143,6 @@ static struct i2c_driver fscher_driver = {
*/
struct fscher_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -283,38 +293,14 @@ static const struct attribute_group fscher_group = {
* Real code
*/
-static int fscher_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, fscher_detect);
-}
-
-static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int fscher_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct fscher_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- * client structure, even though we cannot fill it completely yet.
- * But it allows us to access i2c_smbus_read_byte_data. */
- if (!(data = kzalloc(sizeof(struct fscher_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right before the
- * Hermes-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &fscher_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* Do the remaining detection unless force or force_fscher parameter */
if (kind < 0) {
@@ -324,24 +310,35 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
FSCHER_REG_IDENT_1) != 0x45) /* 'E' */
|| (i2c_smbus_read_byte_data(new_client,
FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */
- goto exit_free;
+ return -ENODEV;
+ }
+
+ strlcpy(info->type, "fscher", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int fscher_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct fscher_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct fscher_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
}
- /* Fill in the remaining client fields and put it into the
- * global list */
- strlcpy(new_client->name, "fscher", I2C_NAME_SIZE);
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
fscher_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -353,25 +350,19 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
-static int fscher_detach_client(struct i2c_client *client)
+static int fscher_remove(struct i2c_client *client)
{
struct fscher_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &fscher_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index bd89d270a5e..96717036893 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -171,20 +171,37 @@ static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
* Functions declarations
*/
-static int fschmd_attach_adapter(struct i2c_adapter *adapter);
-static int fschmd_detach_client(struct i2c_client *client);
+static int fschmd_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int fschmd_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int fschmd_remove(struct i2c_client *client);
static struct fschmd_data *fschmd_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id fschmd_id[] = {
+ { "fscpos", fscpos },
+ { "fscher", fscher },
+ { "fscscy", fscscy },
+ { "fschrc", fschrc },
+ { "fschmd", fschmd },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, fschmd_id);
+
static struct i2c_driver fschmd_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = FSCHMD_NAME,
},
- .attach_adapter = fschmd_attach_adapter,
- .detach_client = fschmd_detach_client,
+ .probe = fschmd_probe,
+ .remove = fschmd_remove,
+ .id_table = fschmd_id,
+ .detect = fschmd_detect,
+ .address_data = &addr_data,
};
/*
@@ -192,7 +209,6 @@ static struct i2c_driver fschmd_driver = {
*/
struct fschmd_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
int kind;
@@ -269,7 +285,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
v = SENSORS_LIMIT(v, -128, 127) + 128;
mutex_lock(&data->update_lock);
- i2c_smbus_write_byte_data(&data->client,
+ i2c_smbus_write_byte_data(to_i2c_client(dev),
FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
data->temp_max[index] = v;
mutex_unlock(&data->update_lock);
@@ -346,14 +362,14 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
mutex_lock(&data->update_lock);
- reg = i2c_smbus_read_byte_data(&data->client,
+ reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
/* bits 2..7 reserved => mask with 0x03 */
reg &= ~0x03;
reg |= v;
- i2c_smbus_write_byte_data(&data->client,
+ i2c_smbus_write_byte_data(to_i2c_client(dev),
FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
data->fan_ripple[index] = reg;
@@ -416,7 +432,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
mutex_lock(&data->update_lock);
- i2c_smbus_write_byte_data(&data->client,
+ i2c_smbus_write_byte_data(to_i2c_client(dev),
FSCHMD_REG_FAN_MIN[data->kind][index], v);
data->fan_min[index] = v;
@@ -448,14 +464,14 @@ static ssize_t store_alert_led(struct device *dev,
mutex_lock(&data->update_lock);
- reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);
+ reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
if (v)
reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
else
reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
- i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);
+ i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
data->global_control = reg;
@@ -600,32 +616,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header)
}
}
-static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
+static int fschmd_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct fschmd_data *data;
- u8 revision;
- const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
- "Heracles", "Heimdall" };
+ struct i2c_adapter *adapter = client->adapter;
const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
"fschrc", "fschmd" };
- int i, err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return 0;
-
- /* OK. For now, we presume we have a valid client. We now create the
- * client structure, even though we cannot fill it completely yet.
- * But it allows us to access i2c_smbus_read_byte_data. */
- if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))
- return -ENOMEM;
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &fschmd_driver;
- mutex_init(&data->update_lock);
+ return -ENODEV;
/* Detect & Identify the chip */
if (kind <= 0) {
@@ -650,9 +649,31 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
else if (!strcmp(id, "HMD"))
kind = fschmd;
else
- goto exit_free;
+ return -ENODEV;
}
+ strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int fschmd_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fschmd_data *data;
+ u8 revision;
+ const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
+ "Heracles", "Heimdall" };
+ int i, err;
+ enum chips kind = id->driver_data;
+
+ data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
if (kind == fscpos) {
/* The Poseidon has hardwired temp limits, fill these
in for the alarm resetting code */
@@ -674,11 +695,6 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
data->kind = kind - 1;
- strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
err = device_create_file(&client->dev,
@@ -726,25 +742,14 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_detach:
- fschmd_detach_client(client); /* will also free data for us */
- return err;
-
-exit_free:
- kfree(data);
+ fschmd_remove(client); /* will also free data for us */
return err;
}
-static int fschmd_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, fschmd_detect);
-}
-
-static int fschmd_detach_client(struct i2c_client *client)
+static int fschmd_remove(struct i2c_client *client)
{
struct fschmd_data *data = i2c_get_clientdata(client);
- int i, err;
+ int i;
/* Check if registered in case we're called from fschmd_detect
to cleanup after an error */
@@ -760,9 +765,6 @@ static int fschmd_detach_client(struct i2c_client *client)
device_remove_file(&client->dev,
&fschmd_fan_attr[i].dev_attr);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 00f48484e54..8a7bcf500b4 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -87,9 +87,11 @@ static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 };
/*
* Functions declaration
*/
-static int fscpos_attach_adapter(struct i2c_adapter *adapter);
-static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind);
-static int fscpos_detach_client(struct i2c_client *client);
+static int fscpos_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int fscpos_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int fscpos_remove(struct i2c_client *client);
static int fscpos_read_value(struct i2c_client *client, u8 reg);
static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value);
@@ -101,19 +103,27 @@ static void reset_fan_alarm(struct i2c_client *client, int nr);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id fscpos_id[] = {
+ { "fscpos", fscpos },
+ { }
+};
+
static struct i2c_driver fscpos_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "fscpos",
},
- .attach_adapter = fscpos_attach_adapter,
- .detach_client = fscpos_detach_client,
+ .probe = fscpos_probe,
+ .remove = fscpos_remove,
+ .id_table = fscpos_id,
+ .detect = fscpos_detect,
+ .address_data = &addr_data,
};
/*
* Client data (each client gets its own)
*/
struct fscpos_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* 0 until following fields are valid */
@@ -470,39 +480,14 @@ static const struct attribute_group fscpos_group = {
.attrs = fscpos_attributes,
};
-static int fscpos_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, fscpos_detect);
-}
-
-static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int fscpos_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct fscpos_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- /*
- * OK. For now, we presume we have a valid client. We now create the
- * client structure, even though we cannot fill it completely yet.
- * But it allows us to access fscpos_{read,write}_value.
- */
-
- if (!(data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &fscpos_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* Do the remaining detection unless force or force_fscpos parameter */
if (kind < 0) {
@@ -512,22 +497,30 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
!= 0x45) /* 'E' */
|| (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2)
!= 0x47))/* 'G' */
- {
- dev_dbg(&new_client->dev, "fscpos detection failed\n");
- goto exit_free;
- }
+ return -ENODEV;
}
- /* Fill in the remaining client fields and put it in the global list */
- strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE);
+ strlcpy(info->type, "fscpos", I2C_NAME_SIZE);
+ return 0;
+}
+
+static int fscpos_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct fscpos_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Inizialize the fscpos chip */
fscpos_init_client(new_client);
@@ -536,7 +529,7 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -548,24 +541,19 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
-static int fscpos_detach_client(struct i2c_client *client)
+static int fscpos_remove(struct i2c_client *client)
{
struct fscpos_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
- if ((err = i2c_detach_client(client)))
- return err;
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 33e9e8a8d1c..7820df45d77 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -114,7 +114,6 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/* Each client has this additional data */
struct gl518_data {
- struct i2c_client client;
struct device *hwmon_dev;
enum chips type;
@@ -138,21 +137,33 @@ struct gl518_data {
u8 beep_enable; /* Boolean */
};
-static int gl518_attach_adapter(struct i2c_adapter *adapter);
-static int gl518_detect(struct i2c_adapter *adapter, int address, int kind);
+static int gl518_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int gl518_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void gl518_init_client(struct i2c_client *client);
-static int gl518_detach_client(struct i2c_client *client);
+static int gl518_remove(struct i2c_client *client);
static int gl518_read_value(struct i2c_client *client, u8 reg);
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
static struct gl518_data *gl518_update_device(struct device *dev);
+static const struct i2c_device_id gl518_id[] = {
+ { "gl518sm", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, gl518_id);
+
/* This is the driver that will be inserted */
static struct i2c_driver gl518_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "gl518sm",
},
- .attach_adapter = gl518_attach_adapter,
- .detach_client = gl518_detach_client,
+ .probe = gl518_probe,
+ .remove = gl518_remove,
+ .id_table = gl518_id,
+ .detect = gl518_detect,
+ .address_data = &addr_data,
};
/*
@@ -472,46 +483,23 @@ static const struct attribute_group gl518_group_r80 = {
* Real code
*/
-static int gl518_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, gl518_detect);
-}
-
-static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int gl518_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
+ struct i2c_adapter *adapter = client->adapter;
int i;
- struct i2c_client *client;
- struct gl518_data *data;
- int err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access gl518_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
-
- client->addr = address;
- client->adapter = adapter;
- client->driver = &gl518_driver;
+ return -ENODEV;
/* Now, we do the remaining detection. */
if (kind < 0) {
if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
|| (gl518_read_value(client, GL518_REG_CONF) & 0x80))
- goto exit_free;
+ return -ENODEV;
}
/* Determine the chip type. */
@@ -526,19 +514,32 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Ignoring 'force' parameter for unknown "
"chip at adapter %d, address 0x%02x\n",
- i2c_adapter_id(adapter), address);
- goto exit_free;
+ i2c_adapter_id(adapter), client->addr);
+ return -ENODEV;
}
}
- /* Fill in the remaining client fields */
- strlcpy(client->name, "gl518sm", I2C_NAME_SIZE);
- data->type = kind;
- mutex_init(&data->update_lock);
+ strlcpy(info->type, "gl518sm", I2C_NAME_SIZE);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ return 0;
+}
+
+static int gl518_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct gl518_data *data;
+ int err, revision;
+
+ data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ revision = gl518_read_value(client, GL518_REG_REVISION);
+ data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00;
+ mutex_init(&data->update_lock);
/* Initialize the GL518SM chip */
data->alarm_mask = 0xff;
@@ -546,7 +547,7 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group)))
- goto exit_detach;
+ goto exit_free;
if (data->type == gl518sm_r80)
if ((err = sysfs_create_group(&client->dev.kobj,
&gl518_group_r80)))
@@ -564,8 +565,6 @@ exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &gl518_group);
if (data->type == gl518sm_r80)
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -591,19 +590,15 @@ static void gl518_init_client(struct i2c_client *client)
gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue);
}
-static int gl518_detach_client(struct i2c_client *client)
+static int gl518_remove(struct i2c_client *client)
{
struct gl518_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl518_group);
if (data->type == gl518sm_r80)
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 8984ef14162..19616f2242b 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -79,26 +79,37 @@ static const u8 GL520_REG_TEMP_MAX_HYST[] = { 0x06, 0x18 };
* Function declarations
*/
-static int gl520_attach_adapter(struct i2c_adapter *adapter);
-static int gl520_detect(struct i2c_adapter *adapter, int address, int kind);
+static int gl520_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int gl520_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void gl520_init_client(struct i2c_client *client);
-static int gl520_detach_client(struct i2c_client *client);
+static int gl520_remove(struct i2c_client *client);
static int gl520_read_value(struct i2c_client *client, u8 reg);
static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
static struct gl520_data *gl520_update_device(struct device *dev);
/* Driver data */
+static const struct i2c_device_id gl520_id[] = {
+ { "gl520sm", gl520sm },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, gl520_id);
+
static struct i2c_driver gl520_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "gl520sm",
},
- .attach_adapter = gl520_attach_adapter,
- .detach_client = gl520_detach_client,
+ .probe = gl520_probe,
+ .remove = gl520_remove,
+ .id_table = gl520_id,
+ .detect = gl520_detect,
+ .address_data = &addr_data,
};
/* Client data */
struct gl520_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until the following fields are valid */
@@ -669,37 +680,15 @@ static const struct attribute_group gl520_group_opt = {
* Real code
*/
-static int gl520_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, gl520_detect);
-}
-
-static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int gl520_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct gl520_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access gl520_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &gl520_driver;
+ return -ENODEV;
/* Determine the chip type. */
if (kind < 0) {
@@ -707,24 +696,36 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
dev_dbg(&client->dev, "Unknown chip type, skipping\n");
- goto exit_free;
+ return -ENODEV;
}
}
- /* Fill in the remaining client fields */
- strlcpy(client->name, "gl520sm", I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ strlcpy(info->type, "gl520sm", I2C_NAME_SIZE);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ return 0;
+}
+
+static int gl520_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct gl520_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
/* Initialize the GL520SM chip */
gl520_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
- goto exit_detach;
+ goto exit_free;
if (data->two_temps) {
if ((err = device_create_file(&client->dev,
@@ -764,8 +765,6 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &gl520_group);
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -811,18 +810,14 @@ static void gl520_init_client(struct i2c_client *client)
gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
}
-static int gl520_detach_client(struct i2c_client *client)
+static int gl520_remove(struct i2c_client *client)
{
struct gl520_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl520_group);
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 11628700808..3195a265f0e 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -1,7 +1,7 @@
/*
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
* with integrated fan control
- * Copyright (C) 2004-2006 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
* Based on the lm90 driver.
*
* The LM63 is a sensor chip made by National Semiconductor. It measures
@@ -128,24 +128,36 @@ I2C_CLIENT_INSMOD_1(lm63);
* Functions declaration
*/
-static int lm63_attach_adapter(struct i2c_adapter *adapter);
-static int lm63_detach_client(struct i2c_client *client);
+static int lm63_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int lm63_remove(struct i2c_client *client);
static struct lm63_data *lm63_update_device(struct device *dev);
-static int lm63_detect(struct i2c_adapter *adapter, int address, int kind);
+static int lm63_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void lm63_init_client(struct i2c_client *client);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id lm63_id[] = {
+ { "lm63", lm63 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm63_id);
+
static struct i2c_driver lm63_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm63",
},
- .attach_adapter = lm63_attach_adapter,
- .detach_client = lm63_detach_client,
+ .probe = lm63_probe,
+ .remove = lm63_remove,
+ .id_table = lm63_id,
+ .detect = lm63_detect,
+ .address_data = &addr_data,
};
/*
@@ -153,7 +165,6 @@ static struct i2c_driver lm63_driver = {
*/
struct lm63_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -411,43 +422,14 @@ static const struct attribute_group lm63_group_fan1 = {
* Real code
*/
-static int lm63_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm63_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm63_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *new_client;
- struct lm63_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right before the
- LM63-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm63_driver;
- new_client->flags = 0;
-
- /* Default to an LM63 if forced */
- if (kind == 0)
- kind = lm63;
+ return -ENODEV;
if (kind < 0) { /* must identify */
u8 man_id, chip_id, reg_config1, reg_config2;
@@ -477,25 +459,38 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
dev_dbg(&adapter->dev, "Unsupported chip "
"(man_id=0x%02X, chip_id=0x%02X).\n",
man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
- strlcpy(new_client->name, "lm63", I2C_NAME_SIZE);
+ strlcpy(info->type, "lm63", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int lm63_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct lm63_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the LM63 chip */
lm63_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj,
&lm63_group)))
- goto exit_detach;
+ goto exit_free;
if (data->config & 0x04) { /* tachometer enabled */
if ((err = sysfs_create_group(&new_client->dev.kobj,
&lm63_group_fan1)))
@@ -513,8 +508,6 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -556,18 +549,14 @@ static void lm63_init_client(struct i2c_client *client)
(data->config_fan & 0x20) ? "manual" : "auto");
}
-static int lm63_detach_client(struct i2c_client *client)
+static int lm63_remove(struct i2c_client *client)
{
struct lm63_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm63_group);
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 36d5a8c3ad8..866b401ab6e 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -52,7 +52,6 @@ I2C_CLIENT_INSMOD_1(lm77);
/* Each client has this additional data */
struct lm77_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid;
@@ -65,23 +64,35 @@ struct lm77_data {
u8 alarms;
};
-static int lm77_attach_adapter(struct i2c_adapter *adapter);
-static int lm77_detect(struct i2c_adapter *adapter, int address, int kind);
+static int lm77_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int lm77_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void lm77_init_client(struct i2c_client *client);
-static int lm77_detach_client(struct i2c_client *client);
+static int lm77_remove(struct i2c_client *client);
static u16 lm77_read_value(struct i2c_client *client, u8 reg);
static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value);
static struct lm77_data *lm77_update_device(struct device *dev);
+static const struct i2c_device_id lm77_id[] = {
+ { "lm77", lm77 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm77_id);
+
/* This is the driver that will be inserted */
static struct i2c_driver lm77_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm77",
},
- .attach_adapter = lm77_attach_adapter,
- .detach_client = lm77_detach_client,
+ .probe = lm77_probe,
+ .remove = lm77_remove,
+ .id_table = lm77_id,
+ .detect = lm77_detect,
+ .address_data = &addr_data,
};
/* straight from the datasheet */
@@ -215,13 +226,6 @@ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
-static int lm77_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm77_detect);
-}
-
static struct attribute *lm77_attributes[] = {
&dev_attr_temp1_input.attr,
&dev_attr_temp1_crit.attr,
@@ -240,32 +244,15 @@ static const struct attribute_group lm77_group = {
.attrs = lm77_attributes,
};
-/* This function is called by i2c_probe */
-static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm77_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct lm77_data *data;
- int err = 0;
- const char *name = "";
+ struct i2c_adapter *adapter = new_client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access lm77_{read,write}_value. */
- if (!(data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm77_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* Here comes the remaining detection. Since the LM77 has no
register dedicated to identification, we have to rely on the
@@ -294,7 +281,7 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|| i2c_smbus_read_word_data(new_client, i + 3) != crit
|| i2c_smbus_read_word_data(new_client, i + 4) != min
|| i2c_smbus_read_word_data(new_client, i + 5) != max)
- goto exit_free;
+ return -ENODEV;
/* sign bits */
if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
@@ -302,51 +289,55 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|| ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
|| ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
|| ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
- goto exit_free;
+ return -ENODEV;
/* unused bits */
if (conf & 0xe0)
- goto exit_free;
+ return -ENODEV;
/* 0x06 and 0x07 return the last read value */
cur = i2c_smbus_read_word_data(new_client, 0);
if (i2c_smbus_read_word_data(new_client, 6) != cur
|| i2c_smbus_read_word_data(new_client, 7) != cur)
- goto exit_free;
+ return -ENODEV;
hyst = i2c_smbus_read_word_data(new_client, 2);
if (i2c_smbus_read_word_data(new_client, 6) != hyst
|| i2c_smbus_read_word_data(new_client, 7) != hyst)
- goto exit_free;
+ return -ENODEV;
min = i2c_smbus_read_word_data(new_client, 4);
if (i2c_smbus_read_word_data(new_client, 6) != min
|| i2c_smbus_read_word_data(new_client, 7) != min)
- goto exit_free;
+ return -ENODEV;
}
- /* Determine the chip type - only one kind supported! */
- if (kind <= 0)
- kind = lm77;
+ strlcpy(info->type, "lm77", I2C_NAME_SIZE);
- if (kind == lm77) {
- name = "lm77";
+ return 0;
+}
+
+static int lm77_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct lm77_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
}
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the LM77 chip */
lm77_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -358,20 +349,17 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
-static int lm77_detach_client(struct i2c_client *client)
+static int lm77_remove(struct i2c_client *client)
{
struct lm77_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm77_group);
- i2c_detach_client(client);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 26c91c9d476..bcffc189940 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -108,7 +108,6 @@ static inline long TEMP_FROM_REG(u16 temp)
*/
struct lm80_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -132,10 +131,12 @@ struct lm80_data {
* Functions declaration
*/
-static int lm80_attach_adapter(struct i2c_adapter *adapter);
-static int lm80_detect(struct i2c_adapter *adapter, int address, int kind);
+static int lm80_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int lm80_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void lm80_init_client(struct i2c_client *client);
-static int lm80_detach_client(struct i2c_client *client);
+static int lm80_remove(struct i2c_client *client);
static struct lm80_data *lm80_update_device(struct device *dev);
static int lm80_read_value(struct i2c_client *client, u8 reg);
static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
@@ -144,12 +145,22 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
* Driver data (common to all clients)
*/
+static const struct i2c_device_id lm80_id[] = {
+ { "lm80", lm80 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm80_id);
+
static struct i2c_driver lm80_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm80",
},
- .attach_adapter = lm80_attach_adapter,
- .detach_client = lm80_detach_client,
+ .probe = lm80_probe,
+ .remove = lm80_remove,
+ .id_table = lm80_id,
+ .detect = lm80_detect,
+ .address_data = &addr_data,
};
/*
@@ -383,13 +394,6 @@ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
* Real code
*/
-static int lm80_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm80_detect);
-}
-
static struct attribute *lm80_attributes[] = {
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
@@ -442,53 +446,46 @@ static const struct attribute_group lm80_group = {
.attrs = lm80_attributes,
};
-static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm80_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
+ struct i2c_adapter *adapter = client->adapter;
int i, cur;
- struct i2c_client *client;
- struct lm80_data *data;
- int err = 0;
- const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access lm80_{read,write}_value. */
- if (!(data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &lm80_driver;
+ return -ENODEV;
/* Now, we do the remaining detection. It is lousy. */
if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
- goto error_free;
+ return -ENODEV;
for (i = 0x2a; i <= 0x3d; i++) {
cur = i2c_smbus_read_byte_data(client, i);
if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
|| (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
|| (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
- goto error_free;
+ return -ENODEV;
}
- /* Determine the chip type - only one kind supported! */
- kind = lm80;
- name = "lm80";
+ strlcpy(info->type, "lm80", I2C_NAME_SIZE);
- /* Fill in the remaining client fields */
- strlcpy(client->name, name, I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ return 0;
+}
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto error_free;
+static int lm80_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm80_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
/* Initialize the LM80 chip */
lm80_init_client(client);
@@ -499,7 +496,7 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &lm80_group)))
- goto error_detach;
+ goto error_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -511,23 +508,18 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
error_remove:
sysfs_remove_group(&client->dev.kobj, &lm80_group);
-error_detach:
- i2c_detach_client(client);
error_free:
kfree(data);
exit:
return err;
}
-static int lm80_detach_client(struct i2c_client *client)
+static int lm80_remove(struct i2c_client *client)
{
struct lm80_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm80_group);
- if ((err = i2c_detach_client(client)))
- return err;
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 6a8642fa25f..e59e2d1f080 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -1,7 +1,7 @@
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
*
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
* a sensor chip made by National Semiconductor. It reports up to four
@@ -118,21 +118,34 @@ static const u8 LM83_REG_W_HIGH[] = {
* Functions declaration
*/
-static int lm83_attach_adapter(struct i2c_adapter *adapter);
-static int lm83_detect(struct i2c_adapter *adapter, int address, int kind);
-static int lm83_detach_client(struct i2c_client *client);
+static int lm83_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info);
+static int lm83_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int lm83_remove(struct i2c_client *client);
static struct lm83_data *lm83_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id lm83_id[] = {
+ { "lm83", lm83 },
+ { "lm82", lm82 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm83_id);
+
static struct i2c_driver lm83_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm83",
},
- .attach_adapter = lm83_attach_adapter,
- .detach_client = lm83_detach_client,
+ .probe = lm83_probe,
+ .remove = lm83_remove,
+ .id_table = lm83_id,
+ .detect = lm83_detect,
+ .address_data = &addr_data,
};
/*
@@ -140,7 +153,6 @@ static struct i2c_driver lm83_driver = {
*/
struct lm83_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -278,40 +290,15 @@ static const struct attribute_group lm83_group_opt = {
* Real code
*/
-static int lm83_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm83_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm83_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *new_client;
- struct lm83_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right after the
- * LM83-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm83_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* Now we do the detection and identification. A negative kind
* means that the driver was loaded with no force parameter
@@ -335,8 +322,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG)
& 0x41) != 0x00)) {
dev_dbg(&adapter->dev,
- "LM83 detection failed at 0x%02x.\n", address);
- goto exit_free;
+ "LM83 detection failed at 0x%02x.\n",
+ new_client->addr);
+ return -ENODEV;
}
}
@@ -361,7 +349,7 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
@@ -372,15 +360,27 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
name = "lm82";
}
- /* We can fill in the remaining client fields */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
+ strlcpy(info->type, name, I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int lm83_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct lm83_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/*
* Register sysfs hooks
* The LM82 can only monitor one external diode which is
@@ -389,9 +389,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
*/
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
- goto exit_detach;
+ goto exit_free;
- if (kind == lm83) {
+ if (id->driver_data == lm83) {
if ((err = sysfs_create_group(&new_client->dev.kobj,
&lm83_group_opt)))
goto exit_remove_files;
@@ -408,26 +408,20 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
-static int lm83_detach_client(struct i2c_client *client)
+static int lm83_remove(struct i2c_client *client)
{
struct lm83_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm83_group);
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index e1c183f0aae..21970f0d53a 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -5,7 +5,7 @@
* Philip Edelbrock <phil@netroedge.com>
* Stephen Rousset <stephen.rousset@rocketlogix.com>
* Dan Eaton <dan.eaton@rocketlogix.com>
- * Copyright (C) 2004,2007 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
*
* Original port to Linux 2.6 by Jeff Oliver.
*
@@ -157,22 +157,35 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
* Functions declaration
*/
-static int lm87_attach_adapter(struct i2c_adapter *adapter);
-static int lm87_detect(struct i2c_adapter *adapter, int address, int kind);
+static int lm87_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int lm87_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info);
static void lm87_init_client(struct i2c_client *client);
-static int lm87_detach_client(struct i2c_client *client);
+static int lm87_remove(struct i2c_client *client);
static struct lm87_data *lm87_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id lm87_id[] = {
+ { "lm87", lm87 },
+ { "adm1024", adm1024 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm87_id);
+
static struct i2c_driver lm87_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm87",
},
- .attach_adapter = lm87_attach_adapter,
- .detach_client = lm87_detach_client,
+ .probe = lm87_probe,
+ .remove = lm87_remove,
+ .id_table = lm87_id,
+ .detect = lm87_detect,
+ .address_data = &addr_data,
};
/*
@@ -180,7 +193,6 @@ static struct i2c_driver lm87_driver = {
*/
struct lm87_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -562,13 +574,6 @@ static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
* Real code
*/
-static int lm87_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm87_detect);
-}
-
static struct attribute *lm87_attributes[] = {
&dev_attr_in1_input.attr,
&dev_attr_in1_min.attr,
@@ -656,33 +661,15 @@ static const struct attribute_group lm87_group_opt = {
.attrs = lm87_attributes_opt,
};
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm87_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct lm87_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
static const char *names[] = { "lm87", "adm1024" };
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right before the
- LM87-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm87_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* Default to an LM87 if forced */
if (kind == 0)
@@ -704,20 +691,32 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) {
dev_dbg(&adapter->dev,
"LM87 detection failed at 0x%02x.\n",
- address);
- goto exit_free;
+ new_client->addr);
+ return -ENODEV;
}
}
- /* We can fill in the remaining client fields */
- strlcpy(new_client->name, names[kind - 1], I2C_NAME_SIZE);
+ strlcpy(info->type, names[kind - 1], I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int lm87_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct lm87_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the LM87 chip */
lm87_init_client(new_client);
@@ -732,7 +731,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
- goto exit_detach;
+ goto exit_free;
if (data->channel & CHAN_NO_FAN(0)) {
if ((err = device_create_file(&new_client->dev,
@@ -832,8 +831,6 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -877,18 +874,14 @@ static void lm87_init_client(struct i2c_client *client)
}
}
-static int lm87_detach_client(struct i2c_client *client)
+static int lm87_remove(struct i2c_client *client)
{
struct lm87_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm87_group);
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index d1a3da3dd8e..c24fe36ac78 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -187,23 +187,44 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
* Functions declaration
*/
-static int lm90_attach_adapter(struct i2c_adapter *adapter);
-static int lm90_detect(struct i2c_adapter *adapter, int address,
- int kind);
+static int lm90_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int lm90_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
static void lm90_init_client(struct i2c_client *client);
-static int lm90_detach_client(struct i2c_client *client);
+static int lm90_remove(struct i2c_client *client);
static struct lm90_data *lm90_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id lm90_id[] = {
+ { "adm1032", adm1032 },
+ { "adt7461", adt7461 },
+ { "lm90", lm90 },
+ { "lm86", lm86 },
+ { "lm89", lm99 },
+ { "lm99", lm99 }, /* Missing temperature offset */
+ { "max6657", max6657 },
+ { "max6658", max6657 },
+ { "max6659", max6657 },
+ { "max6680", max6680 },
+ { "max6681", max6680 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm90_id);
+
static struct i2c_driver lm90_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm90",
},
- .attach_adapter = lm90_attach_adapter,
- .detach_client = lm90_detach_client,
+ .probe = lm90_probe,
+ .remove = lm90_remove,
+ .id_table = lm90_id,
+ .detect = lm90_detect,
+ .address_data = &addr_data,
};
/*
@@ -211,7 +232,6 @@ static struct i2c_driver lm90_driver = {
*/
struct lm90_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -477,40 +497,16 @@ static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value)
return 0;
}
-static int lm90_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm90_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm90_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct lm90_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = new_client->adapter;
+ int address = new_client->addr;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right before the
- LM90-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm90_driver;
- new_client->flags = 0;
+ return -ENODEV;
/*
* Now we do the remaining detection. A negative kind means that
@@ -538,7 +534,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
LM90_REG_R_CONFIG1)) < 0
|| (reg_convrate = i2c_smbus_read_byte_data(new_client,
LM90_REG_R_CONVRATE)) < 0)
- goto exit_free;
+ return -ENODEV;
if ((address == 0x4C || address == 0x4D)
&& man_id == 0x01) { /* National Semiconductor */
@@ -546,7 +542,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
if ((reg_config2 = i2c_smbus_read_byte_data(new_client,
LM90_REG_R_CONFIG2)) < 0)
- goto exit_free;
+ return -ENODEV;
if ((reg_config1 & 0x2A) == 0x00
&& (reg_config2 & 0xF8) == 0x00
@@ -610,10 +606,11 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
+ /* Fill the i2c board info */
if (kind == lm90) {
name = "lm90";
} else if (kind == adm1032) {
@@ -621,7 +618,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
/* The ADM1032 supports PEC, but only if combined
transactions are not used. */
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
- new_client->flags |= I2C_CLIENT_PEC;
+ info->flags |= I2C_CLIENT_PEC;
} else if (kind == lm99) {
name = "lm99";
} else if (kind == lm86) {
@@ -633,23 +630,39 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
} else if (kind == adt7461) {
name = "adt7461";
}
+ strlcpy(info->type, name, I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int lm90_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(new_client->dev.parent);
+ struct lm90_data *data;
+ int err;
- /* We can fill in the remaining client fields */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
- data->valid = 0;
- data->kind = kind;
+ data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ i2c_set_clientdata(new_client, data);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
+ /* Set the device type */
+ data->kind = id->driver_data;
+ if (data->kind == adm1032) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+ new_client->flags &= ~I2C_CLIENT_PEC;
+ }
/* Initialize the LM90 chip */
lm90_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
- goto exit_detach;
+ goto exit_free;
if (new_client->flags & I2C_CLIENT_PEC) {
if ((err = device_create_file(&new_client->dev,
&dev_attr_pec)))
@@ -672,8 +685,6 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
device_remove_file(&new_client->dev, &dev_attr_pec);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -710,10 +721,9 @@ static void lm90_init_client(struct i2c_client *client)
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}
-static int lm90_detach_client(struct i2c_client *client)
+static int lm90_remove(struct i2c_client *client)
{
struct lm90_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm90_group);
@@ -722,9 +732,6 @@ static int lm90_detach_client(struct i2c_client *client)
device_remove_file(&client->dev,
&sensor_dev_attr_temp2_offset.dev_attr);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index c31942e0824..b2e00c5a7ee 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -1,6 +1,6 @@
/*
* lm92 - Hardware monitoring driver
- * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
*
* Based on the lm90 driver, with some ideas taken from the lm_sensors
* lm92 driver as well.
@@ -96,7 +96,6 @@ static struct i2c_driver lm92_driver;
/* Client data (each client gets its own) */
struct lm92_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -319,32 +318,15 @@ static const struct attribute_group lm92_group = {
.attrs = lm92_attributes,
};
-/* The following function does more than just detection. If detection
- succeeds, it also registers the new chip. */
-static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm92_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct lm92_data *data;
- int err = 0;
- char *name;
+ struct i2c_adapter *adapter = new_client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* Fill in enough client fields so that we can read from the chip,
- which is required for identication */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm92_driver;
- new_client->flags = 0;
+ return -ENODEV;
/* A negative kind means that the driver was loaded with no force
parameter (default), so we must identify the chip. */
@@ -364,34 +346,36 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
kind = lm92; /* No separate prefix */
}
else
- goto exit_free;
- } else
- if (kind == 0) /* Default to an LM92 if forced */
- kind = lm92;
-
- /* Give it the proper name */
- if (kind == lm92) {
- name = "lm92";
- } else { /* Supposedly cannot happen */
- dev_dbg(&new_client->dev, "Kind out of range?\n");
- goto exit_free;
+ return -ENODEV;
}
- /* Fill in the remaining client fields */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
+ strlcpy(info->type, "lm92", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int lm92_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct lm92_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the i2c subsystem a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the chipset */
lm92_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -403,32 +387,19 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
return err;
}
-static int lm92_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm92_detect);
-}
-
-static int lm92_detach_client(struct i2c_client *client)
+static int lm92_remove(struct i2c_client *client)
{
struct lm92_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm92_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
@@ -438,12 +409,23 @@ static int lm92_detach_client(struct i2c_client *client)
* Module and driver stuff
*/
+static const struct i2c_device_id lm92_id[] = {
+ { "lm92", lm92 },
+ /* max6635 could be added here */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm92_id);
+
static struct i2c_driver lm92_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm92",
},
- .attach_adapter = lm92_attach_adapter,
- .detach_client = lm92_detach_client,
+ .probe = lm92_probe,
+ .remove = lm92_remove,
+ .id_table = lm92_id,
+ .detect = lm92_detect,
+ .address_data = &addr_data,
};
static int __init sensors_lm92_init(void)
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index 5e678f5c883..fc36cadf36f 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -200,7 +200,6 @@ struct block1_t {
* Client-specific data
*/
struct lm93_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
@@ -2501,45 +2500,14 @@ static void lm93_init_client(struct i2c_client *client)
"chip to signal ready!\n");
}
-static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm93_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct lm93_data *data;
- struct i2c_client *client;
-
- int err = -ENODEV, func;
- void (*update)(struct lm93_data *, struct i2c_client *);
-
- /* choose update routine based on bus capabilities */
- func = i2c_get_functionality(adapter);
- if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
- (!disable_block) ) {
- dev_dbg(&adapter->dev,"using SMBus block data transactions\n");
- update = lm93_update_client_full;
- } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
- dev_dbg(&adapter->dev,"disabled SMBus block data "
- "transactions\n");
- update = lm93_update_client_min;
- } else {
- dev_dbg(&adapter->dev,"detect failed, "
- "smbus byte and/or word data not supported!\n");
- goto err_out;
- }
+ struct i2c_adapter *adapter = client->adapter;
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access lm78_{read,write}_value. */
-
- if ( !(data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL))) {
- dev_dbg(&adapter->dev,"out of memory!\n");
- err = -ENOMEM;
- goto err_out;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &lm93_driver;
+ if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN))
+ return -ENODEV;
/* detection */
if (kind < 0) {
@@ -2548,7 +2516,7 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
if (mfr != 0x01) {
dev_dbg(&adapter->dev,"detect failed, "
"bad manufacturer id 0x%02x!\n", mfr);
- goto err_free;
+ return -ENODEV;
}
}
@@ -2563,31 +2531,61 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind == 0)
dev_dbg(&adapter->dev,
"(ignored 'force' parameter)\n");
- goto err_free;
+ return -ENODEV;
}
}
- /* fill in remaining client fields */
- strlcpy(client->name, "lm93", I2C_NAME_SIZE);
+ strlcpy(info->type, "lm93", I2C_NAME_SIZE);
dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
client->name, i2c_adapter_id(client->adapter),
client->addr);
+ return 0;
+}
+
+static int lm93_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm93_data *data;
+ int err, func;
+ void (*update)(struct lm93_data *, struct i2c_client *);
+
+ /* choose update routine based on bus capabilities */
+ func = i2c_get_functionality(client->adapter);
+ if (((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
+ (!disable_block)) {
+ dev_dbg(&client->dev, "using SMBus block data transactions\n");
+ update = lm93_update_client_full;
+ } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
+ dev_dbg(&client->dev, "disabled SMBus block data "
+ "transactions\n");
+ update = lm93_update_client_min;
+ } else {
+ dev_dbg(&client->dev, "detect failed, "
+ "smbus byte and/or word data not supported!\n");
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL);
+ if (!data) {
+ dev_dbg(&client->dev, "out of memory!\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+ i2c_set_clientdata(client, data);
+
/* housekeeping */
data->valid = 0;
data->update = update;
mutex_init(&data->update_lock);
- /* tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto err_free;
-
/* initialize the chip */
lm93_init_client(client);
err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
if (err)
- goto err_detach;
+ goto err_free;
/* Register hwmon driver class */
data->hwmon_dev = hwmon_device_register(&client->dev);
@@ -2597,43 +2595,39 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
-err_detach:
- i2c_detach_client(client);
err_free:
kfree(data);
err_out:
return err;
}
-/* This function is called when:
- * lm93_driver is inserted (when this module is loaded), for each
- available adapter
- * when a new adapter is inserted (and lm93_driver is still present) */
-static int lm93_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, lm93_detect);
-}
-
-static int lm93_detach_client(struct i2c_client *client)
+static int lm93_remove(struct i2c_client *client)
{
struct lm93_data *data = i2c_get_clientdata(client);
- int err = 0;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
- err = i2c_detach_client(client);
- if (!err)
- kfree(data);
- return err;
+ kfree(data);
+ return 0;
}
+static const struct i2c_device_id lm93_id[] = {
+ { "lm93", lm93 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm93_id);
+
static struct i2c_driver lm93_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm93",
},
- .attach_adapter = lm93_attach_adapter,
- .detach_client = lm93_detach_client,
+ .probe = lm93_probe,
+ .remove = lm93_remove,
+ .id_table = lm93_id,
+ .detect = lm93_detect,
+ .address_data = &addr_data,
};
static int __init lm93_init(void)
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 7e7267a0454..1ab1cacad59 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -79,23 +79,34 @@ I2C_CLIENT_INSMOD_1(max1619);
* Functions declaration
*/
-static int max1619_attach_adapter(struct i2c_adapter *adapter);
-static int max1619_detect(struct i2c_adapter *adapter, int address,
- int kind);
+static int max1619_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int max1619_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static void max1619_init_client(struct i2c_client *client);
-static int max1619_detach_client(struct i2c_client *client);
+static int max1619_remove(struct i2c_client *client);
static struct max1619_data *max1619_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id max1619_id[] = {
+ { "max1619", max1619 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max1619_id);
+
static struct i2c_driver max1619_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "max1619",
},
- .attach_adapter = max1619_attach_adapter,
- .detach_client = max1619_detach_client,
+ .probe = max1619_probe,
+ .remove = max1619_remove,
+ .id_table = max1619_id,
+ .detect = max1619_detect,
+ .address_data = &addr_data,
};
/*
@@ -103,7 +114,6 @@ static struct i2c_driver max1619_driver = {
*/
struct max1619_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -208,41 +218,15 @@ static const struct attribute_group max1619_group = {
* Real code
*/
-static int max1619_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, max1619_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max1619_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct max1619_data *data;
- int err = 0;
- const char *name = "";
+ struct i2c_adapter *adapter = new_client->adapter;
u8 reg_config=0, reg_convrate=0, reg_status=0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right before the
- MAX1619-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &max1619_driver;
- new_client->flags = 0;
+ return -ENODEV;
/*
* Now we do the remaining detection. A negative kind means that
@@ -265,8 +249,8 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|| reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) {
dev_dbg(&adapter->dev,
"MAX1619 detection failed at 0x%02x.\n",
- address);
- goto exit_free;
+ new_client->addr);
+ return -ENODEV;
}
}
@@ -285,28 +269,37 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
- if (kind == max1619)
- name = "max1619";
+ strlcpy(info->type, "max1619", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int max1619_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct max1619_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
- /* We can fill in the remaining client fields */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the MAX1619 chip */
max1619_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
- goto exit_detach;
+ goto exit_free;
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -318,8 +311,6 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -341,17 +332,13 @@ static void max1619_init_client(struct i2c_client *client)
config & 0xBF); /* run */
}
-static int max1619_detach_client(struct i2c_client *client)
+static int max1619_remove(struct i2c_client *client)
{
struct max1619_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &max1619_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 52d528b76cc..f27af6a9da4 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -104,22 +104,34 @@ I2C_CLIENT_INSMOD_1(max6650);
#define DIV_FROM_REG(reg) (1 << (reg & 7))
-static int max6650_attach_adapter(struct i2c_adapter *adapter);
-static int max6650_detect(struct i2c_adapter *adapter, int address, int kind);
+static int max6650_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int max6650_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
static int max6650_init_client(struct i2c_client *client);
-static int max6650_detach_client(struct i2c_client *client);
+static int max6650_remove(struct i2c_client *client);
static struct max6650_data *max6650_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static const struct i2c_device_id max6650_id[] = {
+ { "max6650", max6650 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max6650_id);
+
static struct i2c_driver max6650_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "max6650",
},
- .attach_adapter = max6650_attach_adapter,
- .detach_client = max6650_detach_client,
+ .probe = max6650_probe,
+ .remove = max6650_remove,
+ .id_table = max6650_id,
+ .detect = max6650_detect,
+ .address_data = &addr_data,
};
/*
@@ -128,7 +140,6 @@ static struct i2c_driver max6650_driver = {
struct max6650_data
{
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -437,47 +448,21 @@ static struct attribute_group max6650_attr_grp = {
* Real code
*/
-static int max6650_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6650_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON)) {
- dev_dbg(&adapter->dev,
- "FATAL: max6650_attach_adapter class HWMON not set\n");
- return 0;
- }
-
- return i2c_probe(adapter, &addr_data, max6650_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-
-static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *client;
- struct max6650_data *data;
- int err = -ENODEV;
+ struct i2c_adapter *adapter = client->adapter;
+ int address = client->addr;
dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
"byte read mode, skipping.\n");
- return 0;
- }
-
- if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
- dev_err(&adapter->dev, "max6650: out of memory.\n");
- return -ENOMEM;
+ return -ENODEV;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &max6650_driver;
-
/*
* Now we do the remaining detection. A negative kind means that
* the driver was loaded with no force parameter (default), so we
@@ -501,28 +486,40 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
dev_dbg(&adapter->dev,
"max6650: detection failed at 0x%02x.\n", address);
- goto err_free;
+ return -ENODEV;
}
dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
- strlcpy(client->name, "max6650", I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ strlcpy(info->type, "max6650", I2C_NAME_SIZE);
- if ((err = i2c_attach_client(client))) {
- dev_err(&adapter->dev, "max6650: failed to attach client.\n");
- goto err_free;
+ return 0;
+}
+
+static int max6650_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max6650_data *data;
+ int err;
+
+ if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
+ dev_err(&client->dev, "out of memory.\n");
+ return -ENOMEM;
}
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
/*
* Initialize the max6650 chip
*/
- if (max6650_init_client(client))
- goto err_detach;
+ err = max6650_init_client(client);
+ if (err)
+ goto err_free;
err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
if (err)
- goto err_detach;
+ goto err_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (!IS_ERR(data->hwmon_dev))
@@ -531,24 +528,19 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
-err_detach:
- i2c_detach_client(client);
err_free:
kfree(data);
return err;
}
-static int max6650_detach_client(struct i2c_client *client)
+static int max6650_remove(struct i2c_client *client)
{
struct max6650_data *data = i2c_get_clientdata(client);
- int err;
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
hwmon_device_unregister(data->hwmon_dev);
- err = i2c_detach_client(client);
- if (!err)
- kfree(data);
- return err;
+ kfree(data);
+ return 0;
}
static int max6650_init_client(struct i2c_client *client)
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index 3c9db6598ba..8bb5cb532d4 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -96,7 +96,6 @@ static inline int TEMP_FROM_REG(s8 val)
}
struct smsc47m192_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -114,18 +113,29 @@ struct smsc47m192_data {
u8 vrm;
};
-static int smsc47m192_attach_adapter(struct i2c_adapter *adapter);
-static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
- int kind);
-static int smsc47m192_detach_client(struct i2c_client *client);
+static int smsc47m192_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int smsc47m192_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int smsc47m192_remove(struct i2c_client *client);
static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
+static const struct i2c_device_id smsc47m192_id[] = {
+ { "smsc47m192", smsc47m192 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, smsc47m192_id);
+
static struct i2c_driver smsc47m192_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "smsc47m192",
},
- .attach_adapter = smsc47m192_attach_adapter,
- .detach_client = smsc47m192_detach_client,
+ .probe = smsc47m192_probe,
+ .remove = smsc47m192_remove,
+ .id_table = smsc47m192_id,
+ .detect = smsc47m192_detect,
+ .address_data = &addr_data,
};
/* Voltages */
@@ -440,17 +450,6 @@ static const struct attribute_group smsc47m192_group_in4 = {
.attrs = smsc47m192_attributes_in4,
};
-/* This function is called when:
- * smsc47m192_driver is inserted (when this module is loaded), for each
- available adapter
- * when a new adapter is inserted (and smsc47m192_driver is still present) */
-static int smsc47m192_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, smsc47m192_detect);
-}
-
static void smsc47m192_init_client(struct i2c_client *client)
{
int i;
@@ -481,31 +480,15 @@ static void smsc47m192_init_client(struct i2c_client *client)
}
}
-/* This function is called by i2c_probe */
-static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
- int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int smsc47m192_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct smsc47m192_data *data;
- int err = 0;
- int version, config;
+ struct i2c_adapter *adapter = client->adapter;
+ int version;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &smsc47m192_driver;
-
- if (kind == 0)
- kind = smsc47m192;
+ return -ENODEV;
/* Detection criteria from sensors_detect script */
if (kind < 0) {
@@ -523,26 +506,39 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
} else {
dev_dbg(&adapter->dev,
"SMSC47M192 detection failed at 0x%02x\n",
- address);
- goto exit_free;
+ client->addr);
+ return -ENODEV;
}
}
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
+ strlcpy(info->type, "smsc47m192", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int smsc47m192_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct smsc47m192_data *data;
+ int config;
+ int err;
+
+ data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
data->vrm = vid_which_vrm();
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
/* Initialize the SMSC47M192 chip */
smsc47m192_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
- goto exit_detach;
+ goto exit_free;
/* Pin 110 is either in4 (+12V) or VID4 */
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
@@ -563,26 +559,20 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int smsc47m192_detach_client(struct i2c_client *client)
+static int smsc47m192_remove(struct i2c_client *client)
{
struct smsc47m192_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 76a3859c3fb..3b01001108c 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -60,7 +60,6 @@ static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
/* Each client has this additional data */
struct thmc50_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
@@ -77,17 +76,31 @@ struct thmc50_data {
u8 alarms;
};
-static int thmc50_attach_adapter(struct i2c_adapter *adapter);
-static int thmc50_detach_client(struct i2c_client *client);
+static int thmc50_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int thmc50_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int thmc50_remove(struct i2c_client *client);
static void thmc50_init_client(struct i2c_client *client);
static struct thmc50_data *thmc50_update_device(struct device *dev);
+static const struct i2c_device_id thmc50_id[] = {
+ { "adm1022", adm1022 },
+ { "thmc50", thmc50 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, thmc50_id);
+
static struct i2c_driver thmc50_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "thmc50",
},
- .attach_adapter = thmc50_attach_adapter,
- .detach_client = thmc50_detach_client,
+ .probe = thmc50_probe,
+ .remove = thmc50_remove,
+ .id_table = thmc50_id,
+ .detect = thmc50_detect,
+ .address_data = &addr_data,
};
static ssize_t show_analog_out(struct device *dev,
@@ -250,39 +263,23 @@ static const struct attribute_group temp3_group = {
.attrs = temp3_attributes,
};
-static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int thmc50_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
unsigned company;
unsigned revision;
unsigned config;
- struct i2c_client *client;
- struct thmc50_data *data;
- struct device *dev;
+ struct i2c_adapter *adapter = client->adapter;
int err = 0;
const char *type_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("thmc50: detect failed, "
"smbus byte data not supported!\n");
- goto exit;
- }
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access thmc50 registers. */
- if (!(data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL))) {
- pr_debug("thmc50: detect failed, kzalloc failed!\n");
- err = -ENOMEM;
- goto exit;
+ return -ENODEV;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &thmc50_driver;
- dev = &client->dev;
-
pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
client->addr, i2c_adapter_id(client->adapter));
@@ -307,21 +304,22 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
}
if (err == -ENODEV) {
pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
- goto exit_free;
+ return err;
}
- data->type = kind;
if (kind == adm1022) {
int id = i2c_adapter_id(client->adapter);
int i;
type_name = "adm1022";
- data->has_temp3 = (config >> 7) & 1; /* config MSB */
for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
if (adm1022_temp3[i] == id &&
- adm1022_temp3[i + 1] == address) {
+ adm1022_temp3[i + 1] == client->addr) {
/* enable 2nd remote temp */
- data->has_temp3 = 1;
+ config |= (1 << 7);
+ i2c_smbus_write_byte_data(client,
+ THMC50_REG_CONF,
+ config);
break;
}
} else {
@@ -330,19 +328,33 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
type_name, (revision >> 4) - 0xc, revision & 0xf);
- /* Fill in the remaining client fields & put it into the global list */
- strlcpy(client->name, type_name, I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ strlcpy(info->type, type_name, I2C_NAME_SIZE);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ return 0;
+}
+
+static int thmc50_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct thmc50_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL);
+ if (!data) {
+ pr_debug("thmc50: detect failed, kzalloc failed!\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->type = id->driver_data;
+ mutex_init(&data->update_lock);
thmc50_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
- goto exit_detach;
+ goto exit_free;
/* Register ADM1022 sysfs hooks */
if (data->has_temp3)
@@ -364,34 +376,21 @@ exit_remove_sysfs:
sysfs_remove_group(&client->dev.kobj, &temp3_group);
exit_remove_sysfs_thmc50:
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int thmc50_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, thmc50_detect);
-}
-
-static int thmc50_detach_client(struct i2c_client *client)
+static int thmc50_remove(struct i2c_client *client)
{
struct thmc50_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
if (data->has_temp3)
sysfs_remove_group(&client->dev.kobj, &temp3_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
@@ -412,8 +411,8 @@ static void thmc50_init_client(struct i2c_client *client)
}
config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
config |= 0x1; /* start the chip if it is in standby mode */
- if (data->has_temp3)
- config |= 0x80; /* enable 2nd remote temp */
+ if (data->type == adm1022 && (config & (1 << 7)))
+ data->has_temp3 = 1;
i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
}
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 85077c4c803..e4e91c9d480 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -247,7 +247,6 @@ static u8 div_to_reg(int nr, long val)
}
struct w83791d_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
@@ -286,9 +285,11 @@ struct w83791d_data {
u8 vrm; /* hwmon-vid */
};
-static int w83791d_attach_adapter(struct i2c_adapter *adapter);
-static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind);
-static int w83791d_detach_client(struct i2c_client *client);
+static int w83791d_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int w83791d_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int w83791d_remove(struct i2c_client *client);
static int w83791d_read(struct i2c_client *client, u8 register);
static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
@@ -300,12 +301,22 @@ static void w83791d_print_debug(struct w83791d_data *data, struct device *dev);
static void w83791d_init_client(struct i2c_client *client);
+static const struct i2c_device_id w83791d_id[] = {
+ { "w83791d", w83791d },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, w83791d_id);
+
static struct i2c_driver w83791d_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "w83791d",
},
- .attach_adapter = w83791d_attach_adapter,
- .detach_client = w83791d_detach_client,
+ .probe = w83791d_probe,
+ .remove = w83791d_remove,
+ .id_table = w83791d_id,
+ .detect = w83791d_detect,
+ .address_data = &addr_data,
};
/* following are the sysfs callback functions */
@@ -905,49 +916,12 @@ static const struct attribute_group w83791d_group = {
.attrs = w83791d_attributes,
};
-/* This function is called when:
- * w83791d_driver is inserted (when this module is loaded), for each
- available adapter
- * when a new adapter is inserted (and w83791d_driver is still present) */
-static int w83791d_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, w83791d_detect);
-}
-
-static int w83791d_create_subclient(struct i2c_adapter *adapter,
- struct i2c_client *client, int addr,
- struct i2c_client **sub_cli)
-{
- int err;
- struct i2c_client *sub_client;
-
- (*sub_cli) = sub_client =
- kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!(sub_client)) {
- return -ENOMEM;
- }
- sub_client->addr = 0x48 + addr;
- i2c_set_clientdata(sub_client, NULL);
- sub_client->adapter = adapter;
- sub_client->driver = &w83791d_driver;
- strlcpy(sub_client->name, "w83791d subclient", I2C_NAME_SIZE);
- if ((err = i2c_attach_client(sub_client))) {
- dev_err(&client->dev, "subclient registration "
- "at address 0x%x failed\n", sub_client->addr);
- kfree(sub_client);
- return err;
- }
- return 0;
-}
-
-
-static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
- int kind, struct i2c_client *client)
+static int w83791d_detect_subclients(struct i2c_client *client)
{
+ struct i2c_adapter *adapter = client->adapter;
struct w83791d_data *data = i2c_get_clientdata(client);
+ int address = client->addr;
int i, id, err;
u8 val;
@@ -971,10 +945,7 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
if (!(val & 0x08)) {
- err = w83791d_create_subclient(adapter, client,
- val & 0x7, &data->lm75[0]);
- if (err < 0)
- goto error_sc_0;
+ data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
}
if (!(val & 0x80)) {
if ((data->lm75[0] != NULL) &&
@@ -986,10 +957,8 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
err = -ENODEV;
goto error_sc_1;
}
- err = w83791d_create_subclient(adapter, client,
- (val >> 4) & 0x7, &data->lm75[1]);
- if (err < 0)
- goto error_sc_1;
+ data->lm75[1] = i2c_new_dummy(adapter,
+ 0x48 + ((val >> 4) & 0x7));
}
return 0;
@@ -997,53 +966,31 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
/* Undo inits in case of errors */
error_sc_1:
- if (data->lm75[0] != NULL) {
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[0]);
- }
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
error_sc_0:
return err;
}
-static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83791d_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct device *dev;
- struct w83791d_data *data;
- int i, val1, val2;
- int err = 0;
- const char *client_name = "";
+ struct i2c_adapter *adapter = client->adapter;
+ int val1, val2;
+ unsigned short address = client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- goto error0;
+ return -ENODEV;
}
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access w83791d_{read,write}_value. */
- if (!(data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto error0;
- }
-
- client = &data->client;
- dev = &client->dev;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &w83791d_driver;
- mutex_init(&data->update_lock);
-
- /* Now, we do the remaining detection. */
-
/* The w83791d may be stuck in some other bank than bank 0. This may
make reading other information impossible. Specify a force=...
parameter, and the Winbond will be reset to the right bank. */
if (kind < 0) {
if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) {
- dev_dbg(dev, "Detection failed at step 1\n");
- goto error1;
+ return -ENODEV;
}
val1 = w83791d_read(client, W83791D_REG_BANK);
val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
@@ -1052,15 +999,13 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
/* yes it is Bank0 */
if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
((val1 & 0x80) && (val2 != 0x5c))) {
- dev_dbg(dev, "Detection failed at step 2\n");
- goto error1;
+ return -ENODEV;
}
}
/* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
should match */
if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) {
- dev_dbg(dev, "Detection failed at step 3\n");
- goto error1;
+ return -ENODEV;
}
}
@@ -1075,30 +1020,33 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
/* get vendor ID */
val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
if (val2 != 0x5c) { /* the vendor is NOT Winbond */
- dev_dbg(dev, "Detection failed at step 4\n");
- goto error1;
+ return -ENODEV;
}
val1 = w83791d_read(client, W83791D_REG_WCHIPID);
if (val1 == 0x71) {
kind = w83791d;
} else {
if (kind == 0)
- dev_warn(dev,
+ dev_warn(&adapter->dev,
"w83791d: Ignoring 'force' parameter "
"for unknown chip at adapter %d, "
"address 0x%02x\n",
i2c_adapter_id(adapter), address);
- goto error1;
+ return -ENODEV;
}
}
- if (kind == w83791d) {
- client_name = "w83791d";
- } else {
- dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?\n",
- kind);
- goto error1;
- }
+ strlcpy(info->type, "w83791d", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int w83791d_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct w83791d_data *data;
+ struct device *dev = &client->dev;
+ int i, val1, err;
#ifdef DEBUG
val1 = w83791d_read(client, W83791D_REG_DID_VID4);
@@ -1106,15 +1054,18 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
(val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
#endif
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, client_name, I2C_NAME_SIZE);
+ data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto error0;
+ }
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto error1;
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
- if ((err = w83791d_detect_subclients(adapter, address, kind, client)))
- goto error2;
+ err = w83791d_detect_subclients(client);
+ if (err)
+ goto error1;
/* Initialize the chip */
w83791d_init_client(client);
@@ -1141,43 +1092,29 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
error4:
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
error3:
- if (data->lm75[0] != NULL) {
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[0]);
- }
- if (data->lm75[1] != NULL) {
- i2c_detach_client(data->lm75[1]);
- kfree(data->lm75[1]);
- }
-error2:
- i2c_detach_client(client);
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
+ if (data->lm75[1] != NULL)
+ i2c_unregister_device(data->lm75[1]);
error1:
kfree(data);
error0:
return err;
}
-static int w83791d_detach_client(struct i2c_client *client)
+static int w83791d_remove(struct i2c_client *client)
{
struct w83791d_data *data = i2c_get_clientdata(client);
- int err;
-
- /* main client */
- if (data) {
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &w83791d_group);
- }
- if ((err = i2c_detach_client(client)))
- return err;
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83791d_group);
- /* main client */
- if (data)
- kfree(data);
- /* subclient */
- else
- kfree(client);
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
+ if (data->lm75[1] != NULL)
+ i2c_unregister_device(data->lm75[1]);
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 299629d47ed..cf94c5b0c87 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -267,9 +267,7 @@ DIV_TO_REG(long val)
}
struct w83792d_data {
- struct i2c_client client;
struct device *hwmon_dev;
- enum chips type;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -299,9 +297,11 @@ struct w83792d_data {
u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */
};
-static int w83792d_attach_adapter(struct i2c_adapter *adapter);
-static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind);
-static int w83792d_detach_client(struct i2c_client *client);
+static int w83792d_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int w83792d_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int w83792d_remove(struct i2c_client *client);
static struct w83792d_data *w83792d_update_device(struct device *dev);
#ifdef DEBUG
@@ -310,12 +310,22 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
static void w83792d_init_client(struct i2c_client *client);
+static const struct i2c_device_id w83792d_id[] = {
+ { "w83792d", w83792d },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, w83792d_id);
+
static struct i2c_driver w83792d_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "w83792d",
},
- .attach_adapter = w83792d_attach_adapter,
- .detach_client = w83792d_detach_client,
+ .probe = w83792d_probe,
+ .remove = w83792d_remove,
+ .id_table = w83792d_id,
+ .detect = w83792d_detect,
+ .address_data = &addr_data,
};
static inline long in_count_from_reg(int nr, struct w83792d_data *data)
@@ -864,53 +874,14 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
return count;
}
-/* This function is called when:
- * w83792d_driver is inserted (when this module is loaded), for each
- available adapter
- * when a new adapter is inserted (and w83792d_driver is still present) */
-static int
-w83792d_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, w83792d_detect);
-}
-
-
-static int
-w83792d_create_subclient(struct i2c_adapter *adapter,
- struct i2c_client *new_client, int addr,
- struct i2c_client **sub_cli)
-{
- int err;
- struct i2c_client *sub_client;
-
- (*sub_cli) = sub_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!(sub_client)) {
- return -ENOMEM;
- }
- sub_client->addr = 0x48 + addr;
- i2c_set_clientdata(sub_client, NULL);
- sub_client->adapter = adapter;
- sub_client->driver = &w83792d_driver;
- sub_client->flags = 0;
- strlcpy(sub_client->name, "w83792d subclient", I2C_NAME_SIZE);
- if ((err = i2c_attach_client(sub_client))) {
- dev_err(&new_client->dev, "subclient registration "
- "at address 0x%x failed\n", sub_client->addr);
- kfree(sub_client);
- return err;
- }
- return 0;
-}
-
static int
-w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
- struct i2c_client *new_client)
+w83792d_detect_subclients(struct i2c_client *new_client)
{
int i, id, err;
+ int address = new_client->addr;
u8 val;
+ struct i2c_adapter *adapter = new_client->adapter;
struct w83792d_data *data = i2c_get_clientdata(new_client);
id = i2c_adapter_id(adapter);
@@ -932,10 +903,7 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
if (!(val & 0x08)) {
- err = w83792d_create_subclient(adapter, new_client, val & 0x7,
- &data->lm75[0]);
- if (err < 0)
- goto ERROR_SC_0;
+ data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
}
if (!(val & 0x80)) {
if ((data->lm75[0] != NULL) &&
@@ -945,10 +913,8 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
err = -ENODEV;
goto ERROR_SC_1;
}
- err = w83792d_create_subclient(adapter, new_client,
- (val >> 4) & 0x7, &data->lm75[1]);
- if (err < 0)
- goto ERROR_SC_1;
+ data->lm75[1] = i2c_new_dummy(adapter,
+ 0x48 + ((val >> 4) & 0x7));
}
return 0;
@@ -956,10 +922,8 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
/* Undo inits in case of errors */
ERROR_SC_1:
- if (data->lm75[0] != NULL) {
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[0]);
- }
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
ERROR_SC_0:
return err;
}
@@ -1294,47 +1258,25 @@ static const struct attribute_group w83792d_group = {
.attrs = w83792d_attributes,
};
+/* Return 0 if detection is successful, -ENODEV otherwise */
static int
-w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
+w83792d_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)
{
- int i = 0, val1 = 0, val2;
- struct i2c_client *client;
- struct device *dev;
- struct w83792d_data *data;
- int err = 0;
- const char *client_name = "";
+ struct i2c_adapter *adapter = client->adapter;
+ int val1, val2;
+ unsigned short address = client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- goto ERROR0;
- }
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access w83792d_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto ERROR0;
+ return -ENODEV;
}
- client = &data->client;
- dev = &client->dev;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &w83792d_driver;
- client->flags = 0;
-
- /* Now, we do the remaining detection. */
-
/* The w83792d may be stuck in some other bank than bank 0. This may
make reading other information impossible. Specify a force=... or
force_*=... parameter, and the Winbond will be reset to the right
bank. */
if (kind < 0) {
if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) {
- dev_dbg(dev, "Detection failed at step 1\n");
- goto ERROR1;
+ return -ENODEV;
}
val1 = w83792d_read_value(client, W83792D_REG_BANK);
val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
@@ -1342,16 +1284,14 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
if (!(val1 & 0x07)) { /* is Bank0 */
if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
((val1 & 0x80) && (val2 != 0x5c))) {
- dev_dbg(dev, "Detection failed at step 2\n");
- goto ERROR1;
+ return -ENODEV;
}
}
/* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
should match */
if (w83792d_read_value(client,
W83792D_REG_I2C_ADDR) != address) {
- dev_dbg(dev, "Detection failed at step 3\n");
- goto ERROR1;
+ return -ENODEV;
}
}
@@ -1367,45 +1307,48 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
/* get vendor ID */
val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
if (val2 != 0x5c) { /* the vendor is NOT Winbond */
- goto ERROR1;
+ return -ENODEV;
}
val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
if (val1 == 0x7a) {
kind = w83792d;
} else {
if (kind == 0)
- dev_warn(dev,
+ dev_warn(&adapter->dev,
"w83792d: Ignoring 'force' parameter for"
" unknown chip at adapter %d, address"
" 0x%02x\n", i2c_adapter_id(adapter),
address);
- goto ERROR1;
+ return -ENODEV;
}
}
- if (kind == w83792d) {
- client_name = "w83792d";
- } else {
- dev_err(dev, "w83792d: Internal error: unknown kind (%d)?!?\n",
- kind);
- goto ERROR1;
- }
+ strlcpy(info->type, "w83792d", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int
+w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct w83792d_data *data;
+ struct device *dev = &client->dev;
+ int i, val1, err;
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, client_name, I2C_NAME_SIZE);
- data->type = kind;
+ data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto ERROR0;
+ }
+ i2c_set_clientdata(client, data);
data->valid = 0;
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
+ err = w83792d_detect_subclients(client);
+ if (err)
goto ERROR1;
- if ((err = w83792d_detect_subclients(adapter, address,
- kind, client)))
- goto ERROR2;
-
/* Initialize the chip */
w83792d_init_client(client);
@@ -1457,16 +1400,10 @@ exit_remove_files:
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
ERROR3:
- if (data->lm75[0] != NULL) {
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[0]);
- }
- if (data->lm75[1] != NULL) {
- i2c_detach_client(data->lm75[1]);
- kfree(data->lm75[1]);
- }
-ERROR2:
- i2c_detach_client(client);
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
+ if (data->lm75[1] != NULL)
+ i2c_unregister_device(data->lm75[1]);
ERROR1:
kfree(data);
ERROR0:
@@ -1474,30 +1411,23 @@ ERROR0:
}
static int
-w83792d_detach_client(struct i2c_client *client)
+w83792d_remove(struct i2c_client *client)
{
struct w83792d_data *data = i2c_get_clientdata(client);
- int err, i;
-
- /* main client */
- if (data) {
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &w83792d_group);
- for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
- sysfs_remove_group(&client->dev.kobj,
- &w83792d_group_fan[i]);
- }
+ int i;
- if ((err = i2c_detach_client(client)))
- return err;
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83792d_group);
+ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+ sysfs_remove_group(&client->dev.kobj,
+ &w83792d_group_fan[i]);
- /* main client */
- if (data)
- kfree(data);
- /* subclient */
- else
- kfree(client);
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
+ if (data->lm75[1] != NULL)
+ i2c_unregister_device(data->lm75[1]);
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index ed3c019b78c..0a739f1c69b 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -179,7 +179,6 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
}
struct w83793_data {
- struct i2c_client client;
struct i2c_client *lm75[2];
struct device *hwmon_dev;
struct mutex update_lock;
@@ -226,19 +225,31 @@ struct w83793_data {
static u8 w83793_read_value(struct i2c_client *client, u16 reg);
static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
-static int w83793_attach_adapter(struct i2c_adapter *adapter);
-static int w83793_detect(struct i2c_adapter *adapter, int address, int kind);
-static int w83793_detach_client(struct i2c_client *client);
+static int w83793_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int w83793_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int w83793_remove(struct i2c_client *client);
static void w83793_init_client(struct i2c_client *client);
static void w83793_update_nonvolatile(struct device *dev);
static struct w83793_data *w83793_update_device(struct device *dev);
+static const struct i2c_device_id w83793_id[] = {
+ { "w83793", w83793 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, w83793_id);
+
static struct i2c_driver w83793_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "w83793",
},
- .attach_adapter = w83793_attach_adapter,
- .detach_client = w83793_detach_client,
+ .probe = w83793_probe,
+ .remove = w83793_remove,
+ .id_table = w83793_id,
+ .detect = w83793_detect,
+ .address_data = &addr_data,
};
static ssize_t
@@ -1053,89 +1064,51 @@ static void w83793_init_client(struct i2c_client *client)
}
-static int w83793_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, w83793_detect);
-}
-
-static int w83793_detach_client(struct i2c_client *client)
+static int w83793_remove(struct i2c_client *client)
{
struct w83793_data *data = i2c_get_clientdata(client);
struct device *dev = &client->dev;
- int err, i;
+ int i;
- /* main client */
- if (data) {
- hwmon_device_unregister(data->hwmon_dev);
+ hwmon_device_unregister(data->hwmon_dev);
- for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
- device_remove_file(dev,
- &w83793_sensor_attr_2[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
+ device_remove_file(dev,
+ &w83793_sensor_attr_2[i].dev_attr);
- for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
- device_remove_file(dev, &sda_single_files[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
+ device_remove_file(dev, &sda_single_files[i].dev_attr);
- for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
- device_remove_file(dev, &w83793_vid[i].dev_attr);
- device_remove_file(dev, &dev_attr_vrm);
+ for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
+ device_remove_file(dev, &w83793_vid[i].dev_attr);
+ device_remove_file(dev, &dev_attr_vrm);
- for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
- device_remove_file(dev, &w83793_left_fan[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
+ device_remove_file(dev, &w83793_left_fan[i].dev_attr);
- for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
- device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
+ device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
- for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
- device_remove_file(dev, &w83793_temp[i].dev_attr);
- }
+ for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
+ device_remove_file(dev, &w83793_temp[i].dev_attr);
- if ((err = i2c_detach_client(client)))
- return err;
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
+ if (data->lm75[1] != NULL)
+ i2c_unregister_device(data->lm75[1]);
- /* main client */
- if (data)
- kfree(data);
- /* subclient */
- else
- kfree(client);
+ kfree(data);
return 0;
}
static int
-w83793_create_subclient(struct i2c_adapter *adapter,
- struct i2c_client *client, int addr,
- struct i2c_client **sub_cli)
-{
- int err = 0;
- struct i2c_client *sub_client;
-
- (*sub_cli) = sub_client =
- kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (!(sub_client)) {
- return -ENOMEM;
- }
- sub_client->addr = 0x48 + addr;
- i2c_set_clientdata(sub_client, NULL);
- sub_client->adapter = adapter;
- sub_client->driver = &w83793_driver;
- strlcpy(sub_client->name, "w83793 subclient", I2C_NAME_SIZE);
- if ((err = i2c_attach_client(sub_client))) {
- dev_err(&client->dev, "subclient registration "
- "at address 0x%x failed\n", sub_client->addr);
- kfree(sub_client);
- }
- return err;
-}
-
-static int
-w83793_detect_subclients(struct i2c_adapter *adapter, int address,
- int kind, struct i2c_client *client)
+w83793_detect_subclients(struct i2c_client *client)
{
int i, id, err;
+ int address = client->addr;
u8 tmp;
+ struct i2c_adapter *adapter = client->adapter;
struct w83793_data *data = i2c_get_clientdata(client);
id = i2c_adapter_id(adapter);
@@ -1158,11 +1131,7 @@ w83793_detect_subclients(struct i2c_adapter *adapter, int address,
tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
if (!(tmp & 0x08)) {
- err =
- w83793_create_subclient(adapter, client, tmp & 0x7,
- &data->lm75[0]);
- if (err < 0)
- goto ERROR_SC_0;
+ data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7));
}
if (!(tmp & 0x80)) {
if ((data->lm75[0] != NULL)
@@ -1173,10 +1142,8 @@ w83793_detect_subclients(struct i2c_adapter *adapter, int address,
err = -ENODEV;
goto ERROR_SC_1;
}
- err = w83793_create_subclient(adapter, client,
- (tmp >> 4) & 0x7, &data->lm75[1]);
- if (err < 0)
- goto ERROR_SC_1;
+ data->lm75[1] = i2c_new_dummy(adapter,
+ 0x48 + ((tmp >> 4) & 0x7));
}
return 0;
@@ -1184,69 +1151,44 @@ w83793_detect_subclients(struct i2c_adapter *adapter, int address,
/* Undo inits in case of errors */
ERROR_SC_1:
- if (data->lm75[0] != NULL) {
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[0]);
- }
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
ERROR_SC_0:
return err;
}
-static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83793_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- int i;
- u8 tmp, val;
- struct i2c_client *client;
- struct device *dev;
- struct w83793_data *data;
- int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
- int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
- int files_temp = ARRAY_SIZE(w83793_temp) / 6;
- int err = 0;
+ u8 tmp, bank;
+ struct i2c_adapter *adapter = client->adapter;
+ unsigned short address = client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- goto exit;
+ return -ENODEV;
}
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access w83793_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- dev = &client->dev;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &w83793_driver;
+ bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
- data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
-
- /* Now, we do the remaining detection. */
if (kind < 0) {
- tmp = data->bank & 0x80 ? 0x5c : 0xa3;
+ tmp = bank & 0x80 ? 0x5c : 0xa3;
/* Check Winbond vendor ID */
if (tmp != i2c_smbus_read_byte_data(client,
W83793_REG_VENDORID)) {
pr_debug("w83793: Detection failed at check "
"vendor id\n");
- err = -ENODEV;
- goto free_mem;
+ return -ENODEV;
}
/* If Winbond chip, address of chip and W83793_REG_I2C_ADDR
should match */
- if ((data->bank & 0x07) == 0
+ if ((bank & 0x07) == 0
&& i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
(address << 1)) {
pr_debug("w83793: Detection failed at check "
"i2c addr\n");
- err = -ENODEV;
- goto free_mem;
+ return -ENODEV;
}
}
@@ -1255,30 +1197,47 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
Winbond. Determine the chip type now */
if (kind <= 0) {
- if (0x7b == w83793_read_value(client, W83793_REG_CHIPID)) {
+ if (0x7b == i2c_smbus_read_byte_data(client,
+ W83793_REG_CHIPID)) {
kind = w83793;
} else {
if (kind == 0)
dev_warn(&adapter->dev, "w83793: Ignoring "
"'force' parameter for unknown chip "
"at address 0x%02x\n", address);
- err = -ENODEV;
- goto free_mem;
+ return -ENODEV;
}
}
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, "w83793", I2C_NAME_SIZE);
+ strlcpy(info->type, "w83793", I2C_NAME_SIZE);
+
+ return 0;
+}
+static int w83793_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct w83793_data *data;
+ int i, tmp, val, err;
+ int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
+ int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
+ int files_temp = ARRAY_SIZE(w83793_temp) / 6;
+
+ data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
+ err = w83793_detect_subclients(client);
+ if (err)
goto free_mem;
- if ((err = w83793_detect_subclients(adapter, address, kind, client)))
- goto detach_client;
-
/* Initialize the chip */
w83793_init_client(client);
@@ -1459,16 +1418,10 @@ exit_remove:
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
device_remove_file(dev, &w83793_temp[i].dev_attr);
- if (data->lm75[0] != NULL) {
- i2c_detach_client(data->lm75[0]);
- kfree(data->lm75[0]);
- }
- if (data->lm75[1] != NULL) {
- i2c_detach_client(data->lm75[1]);
- kfree(data->lm75[1]);
- }
-detach_client:
- i2c_detach_client(client);
+ if (data->lm75[0] != NULL)
+ i2c_unregister_device(data->lm75[0]);
+ if (data->lm75[1] != NULL)
+ i2c_unregister_device(data->lm75[1]);
free_mem:
kfree(data);
exit:
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 52e268e25da..ea295b9fc4f 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -81,10 +81,11 @@ I2C_CLIENT_INSMOD_1(w83l785ts);
* Functions declaration
*/
-static int w83l785ts_attach_adapter(struct i2c_adapter *adapter);
-static int w83l785ts_detect(struct i2c_adapter *adapter, int address,
- int kind);
-static int w83l785ts_detach_client(struct i2c_client *client);
+static int w83l785ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int w83l785ts_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int w83l785ts_remove(struct i2c_client *client);
static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
@@ -92,12 +93,22 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
* Driver data (common to all clients)
*/
+static const struct i2c_device_id w83l785ts_id[] = {
+ { "w83l785ts", w83l785ts },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, w83l785ts_id);
+
static struct i2c_driver w83l785ts_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "w83l785ts",
},
- .attach_adapter = w83l785ts_attach_adapter,
- .detach_client = w83l785ts_detach_client,
+ .probe = w83l785ts_probe,
+ .remove = w83l785ts_remove,
+ .id_table = w83l785ts_id,
+ .detect = w83l785ts_detect,
+ .address_data = &addr_data,
};
/*
@@ -105,7 +116,6 @@ static struct i2c_driver w83l785ts_driver = {
*/
struct w83l785ts_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -135,40 +145,14 @@ static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1);
* Real code
*/
-static int w83l785ts_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, w83l785ts_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83l785ts_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *new_client;
- struct w83l785ts_data *data;
- int err = 0;
-
+ struct i2c_adapter *adapter = new_client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- if (!(data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* The common I2C client data is placed right before the
- * W83L785TS-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &w83l785ts_driver;
- new_client->flags = 0;
+ return -ENODEV;
/*
* Now we do the remaining detection. A negative kind means that
@@ -188,8 +172,8 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) {
dev_dbg(&adapter->dev,
"W83L785TS-S detection failed at 0x%02x.\n",
- address);
- goto exit_free;
+ new_client->addr);
+ return -ENODEV;
}
}
@@ -214,22 +198,34 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%04X, "
"chip_id=0x%02X).\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
- /* We can fill in the remaining client fields. */
- strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE);
+ strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int w83l785ts_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct w83l785ts_data *data;
+ int err = 0;
+
+ data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
/* Default values in case the first read fails (unlikely). */
data->temp[1] = data->temp[0] = 0;
- /* Tell the I2C layer a new client has arrived. */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/*
* Initialize the W83L785TS chip
* Nothing yet, assume it is already started.
@@ -259,25 +255,20 @@ exit_remove:
&sensor_dev_attr_temp1_input.dev_attr);
device_remove_file(&new_client->dev,
&sensor_dev_attr_temp1_max.dev_attr);
- i2c_detach_client(new_client);
-exit_free:
kfree(data);
exit:
return err;
}
-static int w83l785ts_detach_client(struct i2c_client *client)
+static int w83l785ts_remove(struct i2c_client *client)
{
struct w83l785ts_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_remove_file(&client->dev,
&sensor_dev_attr_temp1_max.dev_attr);
- if ((err = i2c_detach_client(client)))
- return err;
kfree(data);
return 0;
@@ -286,6 +277,18 @@ static int w83l785ts_detach_client(struct i2c_client *client)
static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
{
int value, i;
+ struct device *dev;
+ const char *prefix;
+
+ /* We might be called during detection, at which point the client
+ isn't yet fully initialized, so we can't use dev_dbg on it */
+ if (i2c_get_clientdata(client)) {
+ dev = &client->dev;
+ prefix = "";
+ } else {
+ dev = &client->adapter->dev;
+ prefix = "w83l785ts: ";
+ }
/* Frequent read errors have been reported on Asus boards, so we
* retry on read errors. If it still fails (unlikely), return the
@@ -293,15 +296,15 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
for (i = 1; i <= MAX_RETRIES; i++) {
value = i2c_smbus_read_byte_data(client, reg);
if (value >= 0) {
- dev_dbg(&client->dev, "Read 0x%02x from register "
- "0x%02x.\n", value, reg);
+ dev_dbg(dev, "%sRead 0x%02x from register 0x%02x.\n",
+ prefix, value, reg);
return value;
}
- dev_dbg(&client->dev, "Read failed, will retry in %d.\n", i);
+ dev_dbg(dev, "%sRead failed, will retry in %d.\n", prefix, i);
msleep(i);
}
- dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n",
+ dev_err(dev, "%sCouldn't read value from register 0x%02x.\n", prefix,
reg);
return defval;
}
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index 41e22ddb568..badca769f35 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -121,7 +121,6 @@ DIV_TO_REG(long val)
}
struct w83l786ng_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -146,18 +145,30 @@ struct w83l786ng_data {
u8 tolerance[2];
};
-static int w83l786ng_attach_adapter(struct i2c_adapter *adapter);
-static int w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind);
-static int w83l786ng_detach_client(struct i2c_client *client);
+static int w83l786ng_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int w83l786ng_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int w83l786ng_remove(struct i2c_client *client);
static void w83l786ng_init_client(struct i2c_client *client);
static struct w83l786ng_data *w83l786ng_update_device(struct device *dev);
+static const struct i2c_device_id w83l786ng_id[] = {
+ { "w83l786ng", w83l786ng },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, w83l786ng_id);
+
static struct i2c_driver w83l786ng_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "w83l786ng",
},
- .attach_adapter = w83l786ng_attach_adapter,
- .detach_client = w83l786ng_detach_client,
+ .probe = w83l786ng_probe,
+ .remove = w83l786ng_remove,
+ .id_table = w83l786ng_id,
+ .detect = w83l786ng_detect,
+ .address_data = &addr_data,
};
static u8
@@ -575,42 +586,15 @@ static const struct attribute_group w83l786ng_group = {
};
static int
-w83l786ng_attach_adapter(struct i2c_adapter *adapter)
+w83l786ng_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, w83l786ng_detect);
-}
-
-static int
-w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *client;
- struct device *dev;
- struct w83l786ng_data *data;
- int i, err = 0;
- u8 reg_tmp;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- goto exit;
- }
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access w83l786ng_{read,write}_value. */
-
- if (!(data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
+ return -ENODEV;
}
- client = &data->client;
- dev = &client->dev;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &w83l786ng_driver;
-
/*
* Now we do the remaining detection. A negative kind means that
* the driver was loaded with no force parameter (default), so we
@@ -627,8 +611,8 @@ w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
W83L786NG_REG_CONFIG) & 0x80) != 0x00)) {
dev_dbg(&adapter->dev,
"W83L786NG detection failed at 0x%02x.\n",
- address);
- goto exit_free;
+ client->addr);
+ return -ENODEV;
}
}
@@ -651,17 +635,31 @@ w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%04X, "
"chip_id=0x%02X).\n", man_id, chip_id);
- goto exit_free;
+ return -ENODEV;
}
}
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, "w83l786ng", I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
+ strlcpy(info->type, "w83l786ng", I2C_NAME_SIZE);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ return 0;
+}
+
+static int
+w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct w83l786ng_data *data;
+ int i, err = 0;
+ u8 reg_tmp;
+
+ data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
/* Initialize the chip */
w83l786ng_init_client(client);
@@ -693,25 +691,19 @@ w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
- i2c_detach_client(client);
-exit_free:
kfree(data);
exit:
return err;
}
static int
-w83l786ng_detach_client(struct i2c_client *client)
+w83l786ng_remove(struct i2c_client *client)
{
struct w83l786ng_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
index 2f150e33c74..72872d1e63e 100644
--- a/drivers/i2c/busses/i2c-amd756-s4882.c
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -155,6 +155,16 @@ static int __init amd756_s4882_init(void)
int i, error;
union i2c_smbus_data ioconfig;
+ /* Configure the PCA9556 multiplexer */
+ ioconfig.byte = 0x00; /* All I/O to output mode */
+ error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+ I2C_SMBUS_BYTE_DATA, &ioconfig);
+ if (error) {
+ dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
+ error = -EIO;
+ goto ERROR0;
+ }
+
/* Unregister physical bus */
error = i2c_del_adapter(&amd756_smbus);
if (error) {
@@ -198,22 +208,11 @@ static int __init amd756_s4882_init(void)
s4882_algo[3].smbus_xfer = amd756_access_virt3;
s4882_algo[4].smbus_xfer = amd756_access_virt4;
- /* Configure the PCA9556 multiplexer */
- ioconfig.byte = 0x00; /* All I/O to output mode */
- error = amd756_smbus.algo->smbus_xfer(&amd756_smbus, 0x18, 0,
- I2C_SMBUS_WRITE, 0x03,
- I2C_SMBUS_BYTE_DATA, &ioconfig);
- if (error) {
- dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
- error = -EIO;
- goto ERROR3;
- }
-
/* Register virtual adapters */
for (i = 0; i < 5; i++) {
error = i2c_add_adapter(s4882_adapter+i);
if (error) {
- dev_err(&amd756_smbus.dev,
+ printk(KERN_ERR "i2c-amd756-s4882: "
"Virtual adapter %d registration "
"failed, module not inserted\n", i);
for (i--; i >= 0; i--)
@@ -252,8 +251,8 @@ static void __exit amd756_s4882_exit(void)
/* Restore physical bus */
if (i2c_add_adapter(&amd756_smbus))
- dev_err(&amd756_smbus.dev, "Physical bus restoration "
- "failed\n");
+ printk(KERN_ERR "i2c-amd756-s4882: "
+ "Physical bus restoration failed\n");
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c
index 6a8995dfd0b..d1a4cbcf2aa 100644
--- a/drivers/i2c/busses/i2c-nforce2-s4985.c
+++ b/drivers/i2c/busses/i2c-nforce2-s4985.c
@@ -150,6 +150,16 @@ static int __init nforce2_s4985_init(void)
int i, error;
union i2c_smbus_data ioconfig;
+ /* Configure the PCA9556 multiplexer */
+ ioconfig.byte = 0x00; /* All I/O to output mode */
+ error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+ I2C_SMBUS_BYTE_DATA, &ioconfig);
+ if (error) {
+ dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
+ error = -EIO;
+ goto ERROR0;
+ }
+
/* Unregister physical bus */
if (!nforce2_smbus)
return -ENODEV;
@@ -191,24 +201,13 @@ static int __init nforce2_s4985_init(void)
s4985_algo[3].smbus_xfer = nforce2_access_virt3;
s4985_algo[4].smbus_xfer = nforce2_access_virt4;
- /* Configure the PCA9556 multiplexer */
- ioconfig.byte = 0x00; /* All I/O to output mode */
- error = nforce2_smbus->algo->smbus_xfer(nforce2_smbus, 0x18, 0,
- I2C_SMBUS_WRITE, 0x03,
- I2C_SMBUS_BYTE_DATA, &ioconfig);
- if (error) {
- dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
- error = -EIO;
- goto ERROR3;
- }
-
/* Register virtual adapters */
for (i = 0; i < 5; i++) {
error = i2c_add_adapter(s4985_adapter + i);
if (error) {
- dev_err(&nforce2_smbus->dev,
- "Virtual adapter %d registration "
- "failed, module not inserted\n", i);
+ printk(KERN_ERR "i2c-nforce2-s4985: "
+ "Virtual adapter %d registration "
+ "failed, module not inserted\n", i);
for (i--; i >= 0; i--)
i2c_del_adapter(s4985_adapter + i);
goto ERROR3;
@@ -245,8 +244,8 @@ static void __exit nforce2_s4985_exit(void)
/* Restore physical bus */
if (i2c_add_adapter(nforce2_smbus))
- dev_err(&nforce2_smbus->dev, "Physical bus restoration "
- "failed\n");
+ printk(KERN_ERR "i2c-nforce2-s4985: "
+ "Physical bus restoration failed\n");
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 373ea8d8fe8..2c27193aeaa 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -47,7 +47,6 @@ enum eeprom_nature {
/* Each client has this additional data */
struct eeprom_data {
- struct i2c_client client;
struct mutex update_lock;
u8 valid; /* bitfield, bit!=0 if slice is valid */
unsigned long last_updated[8]; /* In jiffies, 8 slices */
@@ -56,19 +55,6 @@ struct eeprom_data {
};
-static int eeprom_attach_adapter(struct i2c_adapter *adapter);
-static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind);
-static int eeprom_detach_client(struct i2c_client *client);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver eeprom_driver = {
- .driver = {
- .name = "eeprom",
- },
- .attach_adapter = eeprom_attach_adapter,
- .detach_client = eeprom_detach_client,
-};
-
static void eeprom_update_client(struct i2c_client *client, u8 slice)
{
struct eeprom_data *data = i2c_get_clientdata(client);
@@ -148,25 +134,17 @@ static struct bin_attribute eeprom_attr = {
.read = eeprom_read,
};
-static int eeprom_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & (I2C_CLASS_DDC | I2C_CLASS_SPD)))
- return 0;
- return i2c_probe(adapter, &addr_data, eeprom_detect);
-}
-
-/* This function is called by i2c_probe */
-static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int eeprom_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct eeprom_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
/* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
addresses 0x50-0x57, but we only care about 0x50. So decline
attaching to addresses >= 0x51 on DDC buses */
- if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51)
- goto exit;
+ if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51)
+ return -ENODEV;
/* There are four ways we can read the EEPROM data:
(1) I2C block reads (faster, but unsupported by most adapters)
@@ -177,32 +155,33 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
because all known adapters support one of the first two. */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
- goto exit;
+ return -ENODEV;
+
+ strlcpy(info->type, "eeprom", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int eeprom_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct eeprom_data *data;
+ int err;
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- client = &data->client;
memset(data->data, 0xff, EEPROM_SIZE);
i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &eeprom_driver;
-
- /* Fill in the remaining client fields */
- strlcpy(client->name, "eeprom", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
data->nature = UNKNOWN;
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_kfree;
-
/* Detect the Vaio nature of EEPROMs.
We use the "PCG-" or "VGN-" prefix as the signature. */
- if (address == 0x57
+ if (client->addr == 0x57
&& i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
char name[4];
@@ -221,33 +200,42 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
/* create the sysfs eeprom file */
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
if (err)
- goto exit_detach;
+ goto exit_kfree;
return 0;
-exit_detach:
- i2c_detach_client(client);
exit_kfree:
kfree(data);
exit:
return err;
}
-static int eeprom_detach_client(struct i2c_client *client)
+static int eeprom_remove(struct i2c_client *client)
{
- int err;
-
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
-
- err = i2c_detach_client(client);
- if (err)
- return err;
-
kfree(i2c_get_clientdata(client));
return 0;
}
+static const struct i2c_device_id eeprom_id[] = {
+ { "eeprom", 0 },
+ { }
+};
+
+static struct i2c_driver eeprom_driver = {
+ .driver = {
+ .name = "eeprom",
+ },
+ .probe = eeprom_probe,
+ .remove = eeprom_remove,
+ .id_table = eeprom_id,
+
+ .class = I2C_CLASS_DDC | I2C_CLASS_SPD,
+ .detect = eeprom_detect,
+ .address_data = &addr_data,
+};
+
static int __init eeprom_init(void)
{
return i2c_add_driver(&eeprom_driver);
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 5a0285d8b6f..033d9d81ec8 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -53,7 +53,7 @@ I2C_CLIENT_INSMOD_1(max6875);
/* Each client has this additional data */
struct max6875_data {
- struct i2c_client client;
+ struct i2c_client *fake_client;
struct mutex update_lock;
u32 valid;
@@ -61,19 +61,6 @@ struct max6875_data {
unsigned long last_updated[USER_EEPROM_SLICES];
};
-static int max6875_attach_adapter(struct i2c_adapter *adapter);
-static int max6875_detect(struct i2c_adapter *adapter, int address, int kind);
-static int max6875_detach_client(struct i2c_client *client);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver max6875_driver = {
- .driver = {
- .name = "max6875",
- },
- .attach_adapter = max6875_attach_adapter,
- .detach_client = max6875_detach_client,
-};
-
static void max6875_update_slice(struct i2c_client *client, int slice)
{
struct max6875_data *data = i2c_get_clientdata(client);
@@ -159,96 +146,87 @@ static struct bin_attribute user_eeprom_attr = {
.read = max6875_read,
};
-static int max6875_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6875_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- return i2c_probe(adapter, &addr_data, max6875_detect);
-}
-
-/* This function is called by i2c_probe */
-static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *real_client;
- struct i2c_client *fake_client;
- struct max6875_data *data;
- int err;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
| I2C_FUNC_SMBUS_READ_BYTE))
- return 0;
+ return -ENODEV;
/* Only check even addresses */
- if (address & 1)
- return 0;
+ if (client->addr & 1)
+ return -ENODEV;
+
+ strlcpy(info->type, "max6875", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int max6875_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max6875_data *data;
+ int err;
if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
return -ENOMEM;
/* A fake client is created on the odd address */
- if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1);
+ if (!data->fake_client) {
err = -ENOMEM;
- goto exit_kfree1;
+ goto exit_kfree;
}
/* Init real i2c_client */
- real_client = &data->client;
- i2c_set_clientdata(real_client, data);
- real_client->addr = address;
- real_client->adapter = adapter;
- real_client->driver = &max6875_driver;
- strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
+ i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /* Init fake client data */
- i2c_set_clientdata(fake_client, NULL);
- fake_client->addr = address | 1;
- fake_client->adapter = adapter;
- fake_client->driver = &max6875_driver;
- strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
-
- if ((err = i2c_attach_client(real_client)) != 0)
- goto exit_kfree2;
-
- if ((err = i2c_attach_client(fake_client)) != 0)
- goto exit_detach1;
-
- err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
+ err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
if (err)
- goto exit_detach2;
+ goto exit_remove_fake;
return 0;
-exit_detach2:
- i2c_detach_client(fake_client);
-exit_detach1:
- i2c_detach_client(real_client);
-exit_kfree2:
- kfree(fake_client);
-exit_kfree1:
+exit_remove_fake:
+ i2c_unregister_device(data->fake_client);
+exit_kfree:
kfree(data);
return err;
}
-/* Will be called for both the real client and the fake client */
-static int max6875_detach_client(struct i2c_client *client)
+static int max6875_remove(struct i2c_client *client)
{
- int err;
struct max6875_data *data = i2c_get_clientdata(client);
- /* data is NULL for the fake client */
- if (data)
- sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
+ i2c_unregister_device(data->fake_client);
- err = i2c_detach_client(client);
- if (err)
- return err;
+ sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
+ kfree(data);
- if (data) /* real client */
- kfree(data);
- else /* fake client */
- kfree(client);
return 0;
}
+static const struct i2c_device_id max6875_id[] = {
+ { "max6875", 0 },
+ { }
+};
+
+static struct i2c_driver max6875_driver = {
+ .driver = {
+ .name = "max6875",
+ },
+ .probe = max6875_probe,
+ .remove = max6875_remove,
+ .id_table = max6875_id,
+
+ .detect = max6875_detect,
+ .address_data = &addr_data,
+};
+
static int __init max6875_init(void)
{
return i2c_add_driver(&max6875_driver);
diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c
index 58ab7f26be2..270de4e56a8 100644
--- a/drivers/i2c/chips/pca9539.c
+++ b/drivers/i2c/chips/pca9539.c
@@ -14,8 +14,8 @@
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
+/* Addresses to scan: none, device is not autodetected */
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(pca9539);
@@ -32,23 +32,6 @@ enum pca9539_cmd
PCA9539_DIRECTION_1 = 7,
};
-static int pca9539_attach_adapter(struct i2c_adapter *adapter);
-static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind);
-static int pca9539_detach_client(struct i2c_client *client);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver pca9539_driver = {
- .driver = {
- .name = "pca9539",
- },
- .attach_adapter = pca9539_attach_adapter,
- .detach_client = pca9539_detach_client,
-};
-
-struct pca9539_data {
- struct i2c_client client;
-};
-
/* following are the sysfs callback functions */
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -105,77 +88,51 @@ static struct attribute_group pca9539_defattr_group = {
.attrs = pca9539_attributes,
};
-static int pca9539_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int pca9539_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- return i2c_probe(adapter, &addr_data, pca9539_detect);
-}
-
-/* This function is called by i2c_probe */
-static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
-{
- struct i2c_client *client;
- struct pca9539_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet. */
- if (!(data = kzalloc(sizeof(struct pca9539_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &pca9539_driver;
-
- if (kind < 0) {
- /* Detection: the pca9539 only has 8 registers (0-7).
- A read of 7 should succeed, but a read of 8 should fail. */
- if ((i2c_smbus_read_byte_data(client, 7) < 0) ||
- (i2c_smbus_read_byte_data(client, 8) >= 0))
- goto exit_kfree;
- }
-
- strlcpy(client->name, "pca9539", I2C_NAME_SIZE);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_kfree;
+ return -ENODEV;
- /* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj,
- &pca9539_defattr_group);
- if (err)
- goto exit_detach;
+ strlcpy(info->type, "pca9539", I2C_NAME_SIZE);
return 0;
-
-exit_detach:
- i2c_detach_client(client);
-exit_kfree:
- kfree(data);
-exit:
- return err;
}
-static int pca9539_detach_client(struct i2c_client *client)
+static int pca9539_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int err;
+ /* Register sysfs hooks */
+ return sysfs_create_group(&client->dev.kobj,
+ &pca9539_defattr_group);
+}
+static int pca9539_remove(struct i2c_client *client)
+{
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
- kfree(i2c_get_clientdata(client));
return 0;
}
+static const struct i2c_device_id pca9539_id[] = {
+ { "pca9539", 0 },
+ { }
+};
+
+static struct i2c_driver pca9539_driver = {
+ .driver = {
+ .name = "pca9539",
+ },
+ .probe = pca9539_probe,
+ .remove = pca9539_remove,
+ .id_table = pca9539_id,
+
+ .detect = pca9539_detect,
+ .address_data = &addr_data,
+};
+
static int __init pca9539_init(void)
{
return i2c_add_driver(&pca9539_driver);
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index 1b3db2b3ada..6ec309894c8 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -38,37 +38,19 @@
#include <linux/slab.h>
#include <linux/i2c.h>
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = {
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- I2C_CLIENT_END
-};
+/* Addresses to scan: none, device can't be detected */
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
/* Each client has this additional data */
struct pcf8574_data {
- struct i2c_client client;
-
int write; /* Remember last written value */
};
-static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
-static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind);
-static int pcf8574_detach_client(struct i2c_client *client);
static void pcf8574_init_client(struct i2c_client *client);
-/* This is the driver that will be inserted */
-static struct i2c_driver pcf8574_driver = {
- .driver = {
- .name = "pcf8574",
- },
- .attach_adapter = pcf8574_attach_adapter,
- .detach_client = pcf8574_detach_client,
-};
-
/* following are the sysfs callback functions */
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -119,41 +101,22 @@ static const struct attribute_group pcf8574_attr_group = {
* Real code
*/
-static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, pcf8574_detect);
-}
-
-/* This function is called by i2c_probe */
-static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int pcf8574_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct pcf8574_data *data;
- int err = 0;
- const char *client_name = "";
+ struct i2c_adapter *adapter = client->adapter;
+ const char *client_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
- goto exit;
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet. */
- if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &pcf8574_driver;
+ return -ENODEV;
/* Now, we would do the remaining detection. But the PCF8574 is plainly
impossible to detect! Stupid chip. */
/* Determine the chip type */
if (kind <= 0) {
- if (address >= 0x38 && address <= 0x3f)
+ if (client->addr >= 0x38 && client->addr <= 0x3f)
kind = pcf8574a;
else
kind = pcf8574;
@@ -163,40 +126,43 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
client_name = "pcf8574a";
else
client_name = "pcf8574";
+ strlcpy(info->type, client_name, I2C_NAME_SIZE);
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(client->name, client_name, I2C_NAME_SIZE);
+ return 0;
+}
+
+static int pcf8574_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pcf8574_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
/* Initialize the PCF8574 chip */
pcf8574_init_client(client);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group);
if (err)
- goto exit_detach;
+ goto exit_free;
return 0;
- exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int pcf8574_detach_client(struct i2c_client *client)
+static int pcf8574_remove(struct i2c_client *client)
{
- int err;
-
sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(i2c_get_clientdata(client));
return 0;
}
@@ -208,6 +174,24 @@ static void pcf8574_init_client(struct i2c_client *client)
data->write = -EAGAIN;
}
+static const struct i2c_device_id pcf8574_id[] = {
+ { "pcf8574", 0 },
+ { "pcf8574a", 0 },
+ { }
+};
+
+static struct i2c_driver pcf8574_driver = {
+ .driver = {
+ .name = "pcf8574",
+ },
+ .probe = pcf8574_probe,
+ .remove = pcf8574_remove,
+ .id_table = pcf8574_id,
+
+ .detect = pcf8574_detect,
+ .address_data = &addr_data,
+};
+
static int __init pcf8574_init(void)
{
return i2c_add_driver(&pcf8574_driver);
diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c
index 3ea08ac0bfa..07fd7cb3c57 100644
--- a/drivers/i2c/chips/pcf8575.c
+++ b/drivers/i2c/chips/pcf8575.c
@@ -32,11 +32,8 @@
#include <linux/slab.h> /* kzalloc() */
#include <linux/sysfs.h> /* sysfs_create_group() */
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = {
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- I2C_CLIENT_END
-};
+/* Addresses to scan: none, device can't be detected */
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD;
@@ -44,24 +41,9 @@ I2C_CLIENT_INSMOD;
/* Each client has this additional data */
struct pcf8575_data {
- struct i2c_client client;
int write; /* last written value, or error code */
};
-static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
-static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
-static int pcf8575_detach_client(struct i2c_client *client);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver pcf8575_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "pcf8575",
- },
- .attach_adapter = pcf8575_attach_adapter,
- .detach_client = pcf8575_detach_client,
-};
-
/* following are the sysfs callback functions */
static ssize_t show_read(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -126,75 +108,77 @@ static const struct attribute_group pcf8575_attr_group = {
* Real code
*/
-static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int pcf8575_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- return i2c_probe(adapter, &addr_data, pcf8575_detect);
+ struct i2c_adapter *adapter = client->adapter;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ /* This is the place to detect whether the chip at the specified
+ address really is a PCF8575 chip. However, there is no method known
+ to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
+
+ strlcpy(info->type, "pcf8575", I2C_NAME_SIZE);
+
+ return 0;
}
-/* This function is called by i2c_probe */
-static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
+static int pcf8575_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct i2c_client *client;
struct pcf8575_data *data;
- int err = 0;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
- goto exit;
+ int err;
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet. */
data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
- client = &data->client;
i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &pcf8575_driver;
- strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
data->write = -EAGAIN;
- /* This is the place to detect whether the chip at the specified
- address really is a PCF8575 chip. However, there is no method known
- to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
-
- /* Tell the I2C layer a new client has arrived */
- err = i2c_attach_client(client);
- if (err)
- goto exit_free;
-
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
if (err)
- goto exit_detach;
+ goto exit_free;
return 0;
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
-static int pcf8575_detach_client(struct i2c_client *client)
+static int pcf8575_remove(struct i2c_client *client)
{
- int err;
-
sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
-
- err = i2c_detach_client(client);
- if (err)
- return err;
-
kfree(i2c_get_clientdata(client));
return 0;
}
+static const struct i2c_device_id pcf8575_id[] = {
+ { "pcf8575", 0 },
+ { }
+};
+
+static struct i2c_driver pcf8575_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pcf8575",
+ },
+ .probe = pcf8575_probe,
+ .remove = pcf8575_remove,
+ .id_table = pcf8575_id,
+
+ .detect = pcf8575_detect,
+ .address_data = &addr_data,
+};
+
static int __init pcf8575_init(void)
{
return i2c_add_driver(&pcf8575_driver);
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index db735379f22..16ce3e19377 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -72,28 +72,15 @@ MODULE_PARM_DESC(input_mode,
#define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg))
struct pcf8591_data {
- struct i2c_client client;
struct mutex update_lock;
u8 control;
u8 aout;
};
-static int pcf8591_attach_adapter(struct i2c_adapter *adapter);
-static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind);
-static int pcf8591_detach_client(struct i2c_client *client);
static void pcf8591_init_client(struct i2c_client *client);
static int pcf8591_read_channel(struct device *dev, int channel);
-/* This is the driver that will be inserted */
-static struct i2c_driver pcf8591_driver = {
- .driver = {
- .name = "pcf8591",
- },
- .attach_adapter = pcf8591_attach_adapter,
- .detach_client = pcf8591_detach_client,
-};
-
/* following are the sysfs callback functions */
#define show_in_channel(channel) \
static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \
@@ -180,58 +167,46 @@ static const struct attribute_group pcf8591_attr_group_opt = {
/*
* Real code
*/
-static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, pcf8591_detect);
-}
-/* This function is called by i2c_probe */
-static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int pcf8591_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- struct i2c_client *client;
- struct pcf8591_data *data;
- int err = 0;
+ struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
| I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
- goto exit;
+ return -ENODEV;
+
+ /* Now, we would do the remaining detection. But the PCF8591 is plainly
+ impossible to detect! Stupid chip. */
+
+ strlcpy(info->type, "pcf8591", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int pcf8591_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pcf8591_data *data;
+ int err;
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet. */
if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- client = &data->client;
i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &pcf8591_driver;
-
- /* Now, we would do the remaining detection. But the PCF8591 is plainly
- impossible to detect! Stupid chip. */
-
- /* Determine the chip type - only one kind supported! */
- if (kind <= 0)
- kind = pcf8591;
-
- /* Fill in the remaining client fields and put it into the global
- list */
- strlcpy(client->name, "pcf8591", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_kfree;
-
/* Initialize the PCF8591 chip */
pcf8591_init_client(client);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
if (err)
- goto exit_detach;
+ goto exit_kfree;
/* Register input2 if not in "two differential inputs" mode */
if (input_mode != 3) {
@@ -252,24 +227,16 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
exit_sysfs_remove:
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
-exit_detach:
- i2c_detach_client(client);
exit_kfree:
kfree(data);
exit:
return err;
}
-static int pcf8591_detach_client(struct i2c_client *client)
+static int pcf8591_remove(struct i2c_client *client)
{
- int err;
-
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(i2c_get_clientdata(client));
return 0;
}
@@ -316,6 +283,25 @@ static int pcf8591_read_channel(struct device *dev, int channel)
return (10 * value);
}
+static const struct i2c_device_id pcf8591_id[] = {
+ { "pcf8591", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf8591_id);
+
+static struct i2c_driver pcf8591_driver = {
+ .driver = {
+ .name = "pcf8591",
+ },
+ .probe = pcf8591_probe,
+ .remove = pcf8591_remove,
+ .id_table = pcf8591_id,
+
+ .class = I2C_CLASS_HWMON, /* Nearest choice */
+ .detect = pcf8591_detect,
+ .address_data = &addr_data,
+};
+
static int __init pcf8591_init(void)
{
if (input_mode < 0 || input_mode > 3) {
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 0a79f766101..7608df83d6d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -654,6 +654,10 @@ int i2c_del_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+ /* Clear the device structure in case this adapter is ever going to be
+ added again */
+ memset(&adap->dev, 0, sizeof(adap->dev));
+
out_unlock:
mutex_unlock(&core_lock);
return res;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 636af286230..1921b8dbb24 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -179,17 +179,29 @@ config FUJITSU_LAPTOP
tristate "Fujitsu Laptop Extras"
depends on X86
depends on ACPI
+ depends on INPUT
depends on BACKLIGHT_CLASS_DEVICE
---help---
This is a driver for laptops built by Fujitsu:
* P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
* Possibly other Fujitsu laptop models
+ * Tested with S6410 and S7020
- It adds support for LCD brightness control.
+ It adds support for LCD brightness control and some hotkeys.
If you have a Fujitsu laptop, say Y or M here.
+config FUJITSU_LAPTOP_DEBUG
+ bool "Verbose debug mode for Fujitsu Laptop Extras"
+ depends on FUJITSU_LAPTOP
+ default n
+ ---help---
+ Enables extra debug output from the fujitsu extras driver, at the
+ expense of a slight increase in driver size.
+
+ If you are not sure, say N here.
+
config TC1100_WMI
tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
depends on X86 && !X86_64
@@ -219,6 +231,23 @@ config MSI_LAPTOP
If you have an MSI S270 laptop, say Y or M here.
+config COMPAL_LAPTOP
+ tristate "Compal Laptop Extras"
+ depends on X86
+ depends on ACPI_EC
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by Compal:
+
+ Compal FL90/IFL90
+ Compal FL91/IFL91
+ Compal FL92/JFL92
+ Compal FT00/IFT00
+
+ It adds support for Bluetooth, WLAN and LCD brightness control.
+
+ If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here.
+
config SONY_LAPTOP
tristate "Sony Laptop Extras"
depends on X86 && ACPI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1952875a272..a6dac6a2e7e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -5,10 +5,11 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
-obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
-obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
+obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
+obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index dd13a374992..e7a3fe508df 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -22,18 +22,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define ACER_WMI_VERSION "0.1"
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/dmi.h>
+#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/i8042.h>
+#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
@@ -87,6 +87,7 @@ struct acer_quirks {
* Acer ACPI method GUIDs
*/
#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
+#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
@@ -150,6 +151,12 @@ struct acer_data {
int brightness;
};
+struct acer_debug {
+ struct dentry *root;
+ struct dentry *devices;
+ u32 wmid_devices;
+};
+
/* Each low-level interface must define at least some of the following */
struct wmi_interface {
/* The WMI device type */
@@ -160,6 +167,9 @@ struct wmi_interface {
/* Private data for the current interface */
struct acer_data data;
+
+ /* debugfs entries associated with this interface */
+ struct acer_debug debug;
};
/* The static interface pointer, points to the currently detected interface */
@@ -174,7 +184,7 @@ static struct wmi_interface *interface;
struct quirk_entry {
u8 wireless;
u8 mailled;
- u8 brightness;
+ s8 brightness;
u8 bluetooth;
};
@@ -198,6 +208,10 @@ static int dmi_matched(const struct dmi_system_id *dmi)
static struct quirk_entry quirk_unknown = {
};
+static struct quirk_entry quirk_acer_aspire_1520 = {
+ .brightness = -1,
+};
+
static struct quirk_entry quirk_acer_travelmate_2490 = {
.mailled = 1,
};
@@ -207,9 +221,31 @@ static struct quirk_entry quirk_medion_md_98300 = {
.wireless = 1,
};
+static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
+ .wireless = 2,
+};
+
static struct dmi_system_id acer_quirks[] = {
{
.callback = dmi_matched,
+ .ident = "Acer Aspire 1360",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
+ },
+ .driver_data = &quirk_acer_aspire_1520,
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer Aspire 1520",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
+ },
+ .driver_data = &quirk_acer_aspire_1520,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer Aspire 3100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -300,6 +336,15 @@ static struct dmi_system_id acer_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "Fujitsu Siemens Amilo Li 1718",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
+ },
+ .driver_data = &quirk_fujitsu_amilo_li_1718,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Medion MD 98300",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
@@ -393,6 +438,12 @@ struct wmi_interface *iface)
return AE_ERROR;
*value = result & 0x1;
return AE_OK;
+ case 2:
+ err = ec_read(0x71, &result);
+ if (err)
+ return AE_ERROR;
+ *value = result & 0x1;
+ return AE_OK;
default:
err = ec_read(0xA, &result);
if (err)
@@ -506,6 +557,15 @@ static acpi_status AMW0_set_capabilities(void)
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
+ /*
+ * On laptops with this strange GUID (non Acer), normal probing doesn't
+ * work.
+ */
+ if (wmi_has_guid(AMW0_GUID2)) {
+ interface->capability |= ACER_CAP_WIRELESS;
+ return AE_OK;
+ }
+
args.eax = ACER_AMW0_WRITE;
args.ecx = args.edx = 0;
@@ -552,7 +612,8 @@ static acpi_status AMW0_set_capabilities(void)
* appear to use the same EC register for brightness, even if they
* differ for wireless, etc
*/
- interface->capability |= ACER_CAP_BRIGHTNESS;
+ if (quirks->brightness >= 0)
+ interface->capability |= ACER_CAP_BRIGHTNESS;
return AE_OK;
}
@@ -807,7 +868,15 @@ static int read_brightness(struct backlight_device *bd)
static int update_bl_status(struct backlight_device *bd)
{
- set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS);
+ int intensity = bd->props.brightness;
+
+ if (bd->props.power != FB_BLANK_UNBLANK)
+ intensity = 0;
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+ intensity = 0;
+
+ set_u32(intensity, ACER_CAP_BRIGHTNESS);
+
return 0;
}
@@ -829,8 +898,9 @@ static int __devinit acer_backlight_init(struct device *dev)
acer_backlight_device = bd;
+ bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.brightness = max_brightness;
bd->props.max_brightness = max_brightness;
- bd->props.brightness = read_brightness(NULL);
backlight_update_status(bd);
return 0;
}
@@ -894,6 +964,28 @@ static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
show_interface, NULL);
/*
+ * debugfs functions
+ */
+static u32 get_wmid_devices(void)
+{
+ struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+ acpi_status status;
+
+ status = wmi_query_block(WMID_GUID2, 1, &out);
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ obj = (union acpi_object *) out.pointer;
+ if (obj && obj->type == ACPI_TYPE_BUFFER &&
+ obj->buffer.length == sizeof(u32)) {
+ return *((u32 *) obj->buffer.pointer);
+ } else {
+ return 0;
+ }
+}
+
+/*
* Platform device
*/
static int __devinit acer_platform_probe(struct platform_device *device)
@@ -1052,12 +1144,40 @@ error_sysfs:
return retval;
}
+static void remove_debugfs(void)
+{
+ debugfs_remove(interface->debug.devices);
+ debugfs_remove(interface->debug.root);
+}
+
+static int create_debugfs(void)
+{
+ interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
+ if (!interface->debug.root) {
+ printk(ACER_ERR "Failed to create debugfs directory");
+ return -ENOMEM;
+ }
+
+ interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
+ interface->debug.root,
+ &interface->debug.wmid_devices);
+ if (!interface->debug.devices)
+ goto error_debugfs;
+
+ return 0;
+
+error_debugfs:
+ remove_debugfs();
+ return -ENOMEM;
+}
+
static int __init acer_wmi_init(void)
{
int err;
- printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n",
- ACER_WMI_VERSION);
+ printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n");
+
+ find_quirks();
/*
* Detect which ACPI-WMI interface we're using.
@@ -1092,8 +1212,6 @@ static int __init acer_wmi_init(void)
if (wmi_has_guid(AMW0_GUID1))
AMW0_find_mailled();
- find_quirks();
-
if (!interface) {
printk(ACER_ERR "No or unsupported WMI interface, unable to "
"load\n");
@@ -1111,6 +1229,13 @@ static int __init acer_wmi_init(void)
if (err)
return err;
+ if (wmi_has_guid(WMID_GUID2)) {
+ interface->debug.wmid_devices = get_wmid_devices();
+ err = create_debugfs();
+ if (err)
+ return err;
+ }
+
/* Override any initial settings with values from the commandline */
acer_commandline_init();
diff --git a/drivers/misc/compal-laptop.c b/drivers/misc/compal-laptop.c
new file mode 100644
index 00000000000..344b790a625
--- /dev/null
+++ b/drivers/misc/compal-laptop.c
@@ -0,0 +1,404 @@
+/*-*-linux-c-*-*/
+
+/*
+ Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com>
+
+ based on MSI driver
+
+ Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ */
+
+/*
+ * comapl-laptop.c - Compal laptop support.
+ *
+ * This driver exports a few files in /sys/devices/platform/compal-laptop/:
+ *
+ * wlan - wlan subsystem state: contains 0 or 1 (rw)
+ *
+ * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
+ *
+ * raw - raw value taken from embedded controller register (ro)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control subsystem and is
+ * available to userspace under /sys/class/backlight/compal-laptop/.
+ *
+ * This driver might work on other laptops produced by Compal. If you
+ * want to try it you can pass force=1 as argument to the module which
+ * will force it to load even when the DMI data doesn't identify the
+ * laptop as FL9x.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/autoconf.h>
+
+#define COMPAL_DRIVER_VERSION "0.2.6"
+
+#define COMPAL_LCD_LEVEL_MAX 8
+
+#define COMPAL_EC_COMMAND_WIRELESS 0xBB
+#define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9
+
+#define KILLSWITCH_MASK 0x10
+#define WLAN_MASK 0x01
+#define BT_MASK 0x02
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+/* Hardware access */
+
+static int set_lcd_level(int level)
+{
+ if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX)
+ return -EINVAL;
+
+ ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level);
+
+ return 0;
+}
+
+static int get_lcd_level(void)
+{
+ u8 result;
+
+ ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result);
+
+ return (int) result;
+}
+
+static int set_wlan_state(int state)
+{
+ u8 result, value;
+
+ ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+
+ if ((result & KILLSWITCH_MASK) == 0)
+ return -EINVAL;
+ else {
+ if (state)
+ value = (u8) (result | WLAN_MASK);
+ else
+ value = (u8) (result & ~WLAN_MASK);
+ ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
+ }
+
+ return 0;
+}
+
+static int set_bluetooth_state(int state)
+{
+ u8 result, value;
+
+ ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+
+ if ((result & KILLSWITCH_MASK) == 0)
+ return -EINVAL;
+ else {
+ if (state)
+ value = (u8) (result | BT_MASK);
+ else
+ value = (u8) (result & ~BT_MASK);
+ ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
+ }
+
+ return 0;
+}
+
+static int get_wireless_state(int *wlan, int *bluetooth)
+{
+ u8 result;
+
+ ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+
+ if (wlan) {
+ if ((result & KILLSWITCH_MASK) == 0)
+ *wlan = 0;
+ else
+ *wlan = result & WLAN_MASK;
+ }
+
+ if (bluetooth) {
+ if ((result & KILLSWITCH_MASK) == 0)
+ *bluetooth = 0;
+ else
+ *bluetooth = (result & BT_MASK) >> 1;
+ }
+
+ return 0;
+}
+
+/* Backlight device stuff */
+
+static int bl_get_brightness(struct backlight_device *b)
+{
+ return get_lcd_level();
+}
+
+
+static int bl_update_status(struct backlight_device *b)
+{
+ return set_lcd_level(b->props.brightness);
+}
+
+static struct backlight_ops compalbl_ops = {
+ .get_brightness = bl_get_brightness,
+ .update_status = bl_update_status,
+};
+
+static struct backlight_device *compalbl_device;
+
+/* Platform device */
+
+static ssize_t show_wlan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret, enabled;
+
+ ret = get_wireless_state(&enabled, NULL);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_raw(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 result;
+
+ ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
+
+ return sprintf(buf, "%i\n", result);
+}
+
+static ssize_t show_bluetooth(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret, enabled;
+
+ ret = get_wireless_state(NULL, &enabled);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t store_wlan_state(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int state, ret;
+
+ if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
+ return -EINVAL;
+
+ ret = set_wlan_state(state);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t store_bluetooth_state(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int state, ret;
+
+ if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
+ return -EINVAL;
+
+ ret = set_bluetooth_state(state);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
+static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
+static DEVICE_ATTR(raw, 0444, show_raw, NULL);
+
+static struct attribute *compal_attributes[] = {
+ &dev_attr_bluetooth.attr,
+ &dev_attr_wlan.attr,
+ &dev_attr_raw.attr,
+ NULL
+};
+
+static struct attribute_group compal_attribute_group = {
+ .attrs = compal_attributes
+};
+
+static struct platform_driver compal_driver = {
+ .driver = {
+ .name = "compal-laptop",
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *compal_device;
+
+/* Initialization */
+
+static int dmi_check_cb(const struct dmi_system_id *id)
+{
+ printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n",
+ id->ident);
+
+ return 0;
+}
+
+static struct dmi_system_id __initdata compal_dmi_table[] = {
+ {
+ .ident = "FL90/IFL90",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
+ DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "FL90/IFL90",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
+ DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "FL91/IFL91",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
+ DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "FL92/JFL92",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
+ DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "FT00/IFT00",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
+ DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
+ },
+ .callback = dmi_check_cb
+ },
+ { }
+};
+
+static int __init compal_init(void)
+{
+ int ret;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!force && !dmi_check_system(compal_dmi_table))
+ return -ENODEV;
+
+ /* Register backlight stuff */
+
+ compalbl_device = backlight_device_register("compal-laptop", NULL, NULL,
+ &compalbl_ops);
+ if (IS_ERR(compalbl_device))
+ return PTR_ERR(compalbl_device);
+
+ compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1;
+
+ ret = platform_driver_register(&compal_driver);
+ if (ret)
+ goto fail_backlight;
+
+ /* Register platform stuff */
+
+ compal_device = platform_device_alloc("compal-laptop", -1);
+ if (!compal_device) {
+ ret = -ENOMEM;
+ goto fail_platform_driver;
+ }
+
+ ret = platform_device_add(compal_device);
+ if (ret)
+ goto fail_platform_device1;
+
+ ret = sysfs_create_group(&compal_device->dev.kobj,
+ &compal_attribute_group);
+ if (ret)
+ goto fail_platform_device2;
+
+ printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
+ " successfully loaded.\n");
+
+ return 0;
+
+fail_platform_device2:
+
+ platform_device_del(compal_device);
+
+fail_platform_device1:
+
+ platform_device_put(compal_device);
+
+fail_platform_driver:
+
+ platform_driver_unregister(&compal_driver);
+
+fail_backlight:
+
+ backlight_device_unregister(compalbl_device);
+
+ return ret;
+}
+
+static void __exit compal_cleanup(void)
+{
+
+ sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
+ platform_device_unregister(compal_device);
+ platform_driver_unregister(&compal_driver);
+ backlight_device_unregister(compalbl_device);
+
+ printk(KERN_INFO "compal-laptop: driver unloaded.\n");
+}
+
+module_init(compal_init);
+module_exit(compal_cleanup);
+
+MODULE_AUTHOR("Cezary Jackiewicz");
+MODULE_DESCRIPTION("Compal Laptop Support");
+MODULE_VERSION(COMPAL_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
+MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
+MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
+MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
+MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 6d727609097..9e8d79e7e9f 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -87,7 +87,7 @@ enum {
CM_ASL_LID
};
-const char *cm_getv[] = {
+static const char *cm_getv[] = {
"WLDG", NULL, NULL, NULL,
"CAMG", NULL, NULL, NULL,
NULL, "PBLG", NULL, NULL,
@@ -96,7 +96,7 @@ const char *cm_getv[] = {
"CRDG", "LIDG"
};
-const char *cm_setv[] = {
+static const char *cm_setv[] = {
"WLDS", NULL, NULL, NULL,
"CAMS", NULL, NULL, NULL,
"SDSP", "PBLS", "HDPS", NULL,
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index 6d14e8fe153..7a1ef6c262d 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -1,12 +1,14 @@
/*-*-linux-c-*-*/
/*
- Copyright (C) 2007 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
Based on earlier work:
Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
Adrian Yee <brewt-fujitsu@brewt.org>
- Templated from msi-laptop.c which is copyright by its respective authors.
+ Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
+ by its respective authors.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -39,8 +41,17 @@
* registers itself in the Linux backlight control subsystem and is
* available to userspace under /sys/class/backlight/fujitsu-laptop/.
*
- * This driver has been tested on a Fujitsu Lifebook S7020. It should
- * work on most P-series and S-series Lifebooks, but YMMV.
+ * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
+ * also supported by this driver.
+ *
+ * This driver has been tested on a Fujitsu Lifebook S6410 and S7020. It
+ * should work on most P-series and S-series Lifebooks, but YMMV.
+ *
+ * The module parameter use_alt_lcd_levels switches between different ACPI
+ * brightness controls which are used by different Fujitsu laptops. In most
+ * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
+ * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
+ *
*/
#include <linux/module.h>
@@ -49,30 +60,105 @@
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/backlight.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/video_output.h>
#include <linux/platform_device.h>
-#define FUJITSU_DRIVER_VERSION "0.3"
+#define FUJITSU_DRIVER_VERSION "0.4.2"
#define FUJITSU_LCD_N_LEVELS 8
#define ACPI_FUJITSU_CLASS "fujitsu"
#define ACPI_FUJITSU_HID "FUJ02B1"
-#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver"
+#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1"
-
+#define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3"
+#define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
+#define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
+
+#define ACPI_FUJITSU_NOTIFY_CODE1 0x80
+
+#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
+
+/* Hotkey details */
+#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */
+#define DISPLAY_KEY 0x411 /* keys are mapped to KEY_SCREENLOCK (the key with the key symbol) */
+#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */
+#define REST_KEY 0x413 /* KEY_SUSPEND (R key) */
+
+#define MAX_HOTKEY_RINGBUFFER_SIZE 100
+#define RINGBUFFERSIZE 40
+
+/* Debugging */
+#define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": "
+#define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG
+#define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG
+#define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG
+#define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG
+
+#define FUJLAPTOP_DBG_ALL 0xffff
+#define FUJLAPTOP_DBG_ERROR 0x0001
+#define FUJLAPTOP_DBG_WARN 0x0002
+#define FUJLAPTOP_DBG_INFO 0x0004
+#define FUJLAPTOP_DBG_TRACE 0x0008
+
+#define dbg_printk(a_dbg_level, format, arg...) \
+ do { if (dbg_level & a_dbg_level) \
+ printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
+ } while (0)
+#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+ dbg_printk(a_dbg_level, format, ## arg)
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
+
+/* Device controlling the backlight and associated keys */
struct fujitsu_t {
acpi_handle acpi_handle;
+ struct acpi_device *dev;
+ struct input_dev *input;
+ char phys[32];
struct backlight_device *bl_device;
struct platform_device *pf_device;
- unsigned long fuj02b1_state;
+ unsigned int max_brightness;
unsigned int brightness_changed;
unsigned int brightness_level;
};
static struct fujitsu_t *fujitsu;
+static int use_alt_lcd_levels = -1;
+static int disable_brightness_keys = -1;
+static int disable_brightness_adjust = -1;
+
+/* Device used to access other hotkeys on the laptop */
+struct fujitsu_hotkey_t {
+ acpi_handle acpi_handle;
+ struct acpi_device *dev;
+ struct input_dev *input;
+ char phys[32];
+ struct platform_device *pf_device;
+ struct kfifo *fifo;
+ spinlock_t fifo_lock;
+
+ unsigned int irb; /* info about the pressed buttons */
+};
-/* Hardware access */
+static struct fujitsu_hotkey_t *fujitsu_hotkey;
+
+static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
+ void *data);
+
+#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
+static u32 dbg_level = 0x03;
+#endif
+
+static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data);
+
+/* Hardware access for LCD brightness control */
static int set_lcd_level(int level)
{
@@ -81,7 +167,10 @@ static int set_lcd_level(int level)
struct acpi_object_list arg_list = { 1, &arg0 };
acpi_handle handle = NULL;
- if (level < 0 || level >= FUJITSU_LCD_N_LEVELS)
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
+ level);
+
+ if (level < 0 || level >= fujitsu->max_brightness)
return -EINVAL;
if (!fujitsu)
@@ -89,7 +178,38 @@ static int set_lcd_level(int level)
status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n"));
+ vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
+ return -ENODEV;
+ }
+
+ arg0.integer.value = level;
+
+ status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int set_lcd_level_alt(int level)
+{
+ acpi_status status = AE_OK;
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list arg_list = { 1, &arg0 };
+ acpi_handle handle = NULL;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
+ level);
+
+ if (level < 0 || level >= fujitsu->max_brightness)
+ return -EINVAL;
+
+ if (!fujitsu)
+ return -EINVAL;
+
+ status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
+ if (ACPI_FAILURE(status)) {
+ vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
return -ENODEV;
}
@@ -107,13 +227,52 @@ static int get_lcd_level(void)
unsigned long state = 0;
acpi_status status = AE_OK;
- // Get the Brightness
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
+
status =
acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
if (status < 0)
return status;
- fujitsu->fuj02b1_state = state;
+ fujitsu->brightness_level = state & 0x0fffffff;
+
+ if (state & 0x80000000)
+ fujitsu->brightness_changed = 1;
+ else
+ fujitsu->brightness_changed = 0;
+
+ return fujitsu->brightness_level;
+}
+
+static int get_max_brightness(void)
+{
+ unsigned long state = 0;
+ acpi_status status = AE_OK;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
+
+ status =
+ acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
+ if (status < 0)
+ return status;
+
+ fujitsu->max_brightness = state;
+
+ return fujitsu->max_brightness;
+}
+
+static int get_lcd_level_alt(void)
+{
+ unsigned long state = 0;
+ acpi_status status = AE_OK;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n");
+
+ status =
+ acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state);
+ if (status < 0)
+ return status;
+
fujitsu->brightness_level = state & 0x0fffffff;
if (state & 0x80000000)
@@ -128,12 +287,18 @@ static int get_lcd_level(void)
static int bl_get_brightness(struct backlight_device *b)
{
- return get_lcd_level();
+ if (use_alt_lcd_levels)
+ return get_lcd_level_alt();
+ else
+ return get_lcd_level();
}
static int bl_update_status(struct backlight_device *b)
{
- return set_lcd_level(b->props.brightness);
+ if (use_alt_lcd_levels)
+ return set_lcd_level_alt(b->props.brightness);
+ else
+ return set_lcd_level(b->props.brightness);
}
static struct backlight_ops fujitsubl_ops = {
@@ -141,7 +306,35 @@ static struct backlight_ops fujitsubl_ops = {
.update_status = bl_update_status,
};
-/* Platform device */
+/* Platform LCD brightness device */
+
+static ssize_t
+show_max_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ ret = get_max_brightness();
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t
+show_brightness_changed(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ ret = fujitsu->brightness_changed;
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", ret);
+}
static ssize_t show_lcd_level(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -149,7 +342,10 @@ static ssize_t show_lcd_level(struct device *dev,
int ret;
- ret = get_lcd_level();
+ if (use_alt_lcd_levels)
+ ret = get_lcd_level_alt();
+ else
+ ret = get_lcd_level();
if (ret < 0)
return ret;
@@ -164,19 +360,61 @@ static ssize_t store_lcd_level(struct device *dev,
int level, ret;
if (sscanf(buf, "%i", &level) != 1
- || (level < 0 || level >= FUJITSU_LCD_N_LEVELS))
+ || (level < 0 || level >= fujitsu->max_brightness))
return -EINVAL;
- ret = set_lcd_level(level);
+ if (use_alt_lcd_levels)
+ ret = set_lcd_level_alt(level);
+ else
+ ret = set_lcd_level(level);
+ if (ret < 0)
+ return ret;
+
+ if (use_alt_lcd_levels)
+ ret = get_lcd_level_alt();
+ else
+ ret = get_lcd_level();
if (ret < 0)
return ret;
return count;
}
+/* Hardware access for hotkey device */
+
+static int get_irb(void)
+{
+ unsigned long state = 0;
+ acpi_status status = AE_OK;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
+
+ status =
+ acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL,
+ &state);
+ if (status < 0)
+ return status;
+
+ fujitsu_hotkey->irb = state;
+
+ return fujitsu_hotkey->irb;
+}
+
+static ssize_t
+ignore_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return count;
+}
+
+static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
+static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
+ ignore_store);
static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
static struct attribute *fujitsupf_attributes[] = {
+ &dev_attr_brightness_changed.attr,
+ &dev_attr_max_brightness.attr,
&dev_attr_lcd_level.attr,
NULL
};
@@ -192,14 +430,52 @@ static struct platform_driver fujitsupf_driver = {
}
};
-/* ACPI device */
+static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+{
+ acpi_handle handle;
+ int have_blnf;
+ printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n",
+ id->ident);
+ have_blnf = ACPI_SUCCESS
+ (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle));
+ if (use_alt_lcd_levels == -1) {
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n");
+ use_alt_lcd_levels = 1;
+ }
+ if (disable_brightness_keys == -1) {
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "auto-detecting disable_keys\n");
+ disable_brightness_keys = have_blnf ? 1 : 0;
+ }
+ if (disable_brightness_adjust == -1) {
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "auto-detecting disable_adjust\n");
+ disable_brightness_adjust = have_blnf ? 0 : 1;
+ }
+ return 0;
+}
+
+static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
+ {
+ .ident = "Fujitsu Siemens",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
+ },
+ .callback = dmi_check_cb_s6410},
+ {}
+};
+
+/* ACPI device for LCD brightness control */
static int acpi_fujitsu_add(struct acpi_device *device)
{
+ acpi_status status;
+ acpi_handle handle;
int result = 0;
int state = 0;
-
- ACPI_FUNCTION_TRACE("acpi_fujitsu_add");
+ struct input_dev *input;
+ int error;
if (!device)
return -EINVAL;
@@ -209,10 +485,42 @@ static int acpi_fujitsu_add(struct acpi_device *device)
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
acpi_driver_data(device) = fujitsu;
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_fujitsu_notify, fujitsu);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "Error installing notify handler\n");
+ error = -ENODEV;
+ goto err_stop;
+ }
+
+ fujitsu->input = input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto err_uninstall_notify;
+ }
+
+ snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+ "%s/video/input0", acpi_device_hid(device));
+
+ input->name = acpi_device_name(device);
+ input->phys = fujitsu->phys;
+ input->id.bustype = BUS_HOST;
+ input->id.product = 0x06;
+ input->dev.parent = &device->dev;
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_BRIGHTNESSUP, input->keybit);
+ set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
+ set_bit(KEY_UNKNOWN, input->keybit);
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_input_dev;
+
result = acpi_bus_get_power(fujitsu->acpi_handle, &state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error reading power state\n"));
+ printk(KERN_ERR "Error reading power state\n");
goto end;
}
@@ -220,22 +528,373 @@ static int acpi_fujitsu_add(struct acpi_device *device)
acpi_device_name(device), acpi_device_bid(device),
!device->power.state ? "on" : "off");
- end:
+ fujitsu->dev = device;
+
+ if (ACPI_SUCCESS
+ (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) {
+ vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
+ if (ACPI_FAILURE
+ (acpi_evaluate_object
+ (device->handle, METHOD_NAME__INI, NULL, NULL)))
+ printk(KERN_ERR "_INI Method failed\n");
+ }
+
+ /* do config (detect defaults) */
+ dmi_check_system(fujitsu_dmi_table);
+ use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
+ disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0;
+ disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
+ vdbg_printk(FUJLAPTOP_DBG_INFO,
+ "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n",
+ use_alt_lcd_levels, disable_brightness_keys,
+ disable_brightness_adjust);
+
+ if (get_max_brightness() <= 0)
+ fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
+ if (use_alt_lcd_levels)
+ get_lcd_level_alt();
+ else
+ get_lcd_level();
+
+ return result;
+
+end:
+err_free_input_dev:
+ input_free_device(input);
+err_uninstall_notify:
+ acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+ acpi_fujitsu_notify);
+err_stop:
return result;
}
static int acpi_fujitsu_remove(struct acpi_device *device, int type)
{
- ACPI_FUNCTION_TRACE("acpi_fujitsu_remove");
+ acpi_status status;
+ struct fujitsu_t *fujitsu = NULL;
if (!device || !acpi_driver_data(device))
return -EINVAL;
+
+ fujitsu = acpi_driver_data(device);
+
+ status = acpi_remove_notify_handler(fujitsu->acpi_handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_fujitsu_notify);
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
fujitsu->acpi_handle = NULL;
return 0;
}
+/* Brightness notify */
+
+static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct input_dev *input;
+ int keycode;
+ int oldb, newb;
+
+ input = fujitsu->input;
+
+ switch (event) {
+ case ACPI_FUJITSU_NOTIFY_CODE1:
+ keycode = 0;
+ oldb = fujitsu->brightness_level;
+ get_lcd_level(); /* the alt version always yields changed */
+ newb = fujitsu->brightness_level;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "brightness button event [%i -> %i (%i)]\n",
+ oldb, newb, fujitsu->brightness_changed);
+
+ if (oldb == newb && fujitsu->brightness_changed) {
+ keycode = 0;
+ if (disable_brightness_keys != 1) {
+ if (oldb == 0) {
+ acpi_bus_generate_proc_event(fujitsu->
+ dev,
+ ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
+ 0);
+ keycode = KEY_BRIGHTNESSDOWN;
+ } else if (oldb ==
+ (fujitsu->max_brightness) - 1) {
+ acpi_bus_generate_proc_event(fujitsu->
+ dev,
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
+ 0);
+ keycode = KEY_BRIGHTNESSUP;
+ }
+ }
+ } else if (oldb < newb) {
+ if (disable_brightness_adjust != 1) {
+ if (use_alt_lcd_levels)
+ set_lcd_level_alt(newb);
+ else
+ set_lcd_level(newb);
+ }
+ if (disable_brightness_keys != 1) {
+ acpi_bus_generate_proc_event(fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
+ 0);
+ keycode = KEY_BRIGHTNESSUP;
+ }
+ } else if (oldb > newb) {
+ if (disable_brightness_adjust != 1) {
+ if (use_alt_lcd_levels)
+ set_lcd_level_alt(newb);
+ else
+ set_lcd_level(newb);
+ }
+ if (disable_brightness_keys != 1) {
+ acpi_bus_generate_proc_event(fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
+ 0);
+ keycode = KEY_BRIGHTNESSDOWN;
+ }
+ } else {
+ keycode = KEY_UNKNOWN;
+ }
+ break;
+ default:
+ keycode = KEY_UNKNOWN;
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "unsupported event [0x%x]\n", event);
+ break;
+ }
+
+ if (keycode != 0) {
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ }
+
+ return;
+}
+
+/* ACPI device for hotkey handling */
+
+static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
+{
+ acpi_status status;
+ acpi_handle handle;
+ int result = 0;
+ int state = 0;
+ struct input_dev *input;
+ int error;
+ int i;
+
+ if (!device)
+ return -EINVAL;
+
+ fujitsu_hotkey->acpi_handle = device->handle;
+ sprintf(acpi_device_name(device), "%s",
+ ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
+ sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
+ acpi_driver_data(device) = fujitsu_hotkey;
+
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_fujitsu_hotkey_notify,
+ fujitsu_hotkey);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "Error installing notify handler\n");
+ error = -ENODEV;
+ goto err_stop;
+ }
+
+ /* kfifo */
+ spin_lock_init(&fujitsu_hotkey->fifo_lock);
+ fujitsu_hotkey->fifo =
+ kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL,
+ &fujitsu_hotkey->fifo_lock);
+ if (IS_ERR(fujitsu_hotkey->fifo)) {
+ printk(KERN_ERR "kfifo_alloc failed\n");
+ error = PTR_ERR(fujitsu_hotkey->fifo);
+ goto err_stop;
+ }
+
+ fujitsu_hotkey->input = input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto err_uninstall_notify;
+ }
+
+ snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys),
+ "%s/video/input0", acpi_device_hid(device));
+
+ input->name = acpi_device_name(device);
+ input->phys = fujitsu_hotkey->phys;
+ input->id.bustype = BUS_HOST;
+ input->id.product = 0x06;
+ input->dev.parent = &device->dev;
+ input->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_SCREENLOCK, input->keybit);
+ set_bit(KEY_MEDIA, input->keybit);
+ set_bit(KEY_EMAIL, input->keybit);
+ set_bit(KEY_SUSPEND, input->keybit);
+ set_bit(KEY_UNKNOWN, input->keybit);
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_input_dev;
+
+ result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state);
+ if (result) {
+ printk(KERN_ERR "Error reading power state\n");
+ goto end;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ !device->power.state ? "on" : "off");
+
+ fujitsu_hotkey->dev = device;
+
+ if (ACPI_SUCCESS
+ (acpi_get_handle(device->handle, METHOD_NAME__INI, &handle))) {
+ vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
+ if (ACPI_FAILURE
+ (acpi_evaluate_object
+ (device->handle, METHOD_NAME__INI, NULL, NULL)))
+ printk(KERN_ERR "_INI Method failed\n");
+ }
+
+ i = 0; /* Discard hotkey ringbuffer */
+ while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ;
+ vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
+
+ return result;
+
+end:
+err_free_input_dev:
+ input_free_device(input);
+err_uninstall_notify:
+ acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+ acpi_fujitsu_hotkey_notify);
+ kfifo_free(fujitsu_hotkey->fifo);
+err_stop:
+
+ return result;
+}
+
+static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
+{
+ acpi_status status;
+ struct fujitsu_hotkey_t *fujitsu_hotkey = NULL;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ fujitsu_hotkey = acpi_driver_data(device);
+
+ status = acpi_remove_notify_handler(fujitsu_hotkey->acpi_handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_fujitsu_hotkey_notify);
+
+ fujitsu_hotkey->acpi_handle = NULL;
+
+ kfifo_free(fujitsu_hotkey->fifo);
+
+ return 0;
+}
+
+static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
+ void *data)
+{
+ struct input_dev *input;
+ int keycode, keycode_r;
+ unsigned int irb = 1;
+ int i, status;
+
+ input = fujitsu_hotkey->input;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n");
+
+ switch (event) {
+ case ACPI_FUJITSU_NOTIFY_CODE1:
+ i = 0;
+ while ((irb = get_irb()) != 0
+ && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n",
+ irb);
+
+ switch (irb & 0x4ff) {
+ case LOCK_KEY:
+ keycode = KEY_SCREENLOCK;
+ break;
+ case DISPLAY_KEY:
+ keycode = KEY_MEDIA;
+ break;
+ case ENERGY_KEY:
+ keycode = KEY_EMAIL;
+ break;
+ case REST_KEY:
+ keycode = KEY_SUSPEND;
+ break;
+ case 0:
+ keycode = 0;
+ break;
+ default:
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Unknown GIRB result [%x]\n", irb);
+ keycode = -1;
+ break;
+ }
+ if (keycode > 0) {
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "Push keycode into ringbuffer [%d]\n",
+ keycode);
+ status = kfifo_put(fujitsu_hotkey->fifo,
+ (unsigned char *)&keycode,
+ sizeof(keycode));
+ if (status != sizeof(keycode)) {
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Could not push keycode [0x%x]\n",
+ keycode);
+ } else {
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ }
+ } else if (keycode == 0) {
+ while ((status =
+ kfifo_get
+ (fujitsu_hotkey->fifo, (unsigned char *)
+ &keycode_r,
+ sizeof
+ (keycode_r))) == sizeof(keycode_r)) {
+ input_report_key(input, keycode_r, 0);
+ input_sync(input);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "Pop keycode from ringbuffer [%d]\n",
+ keycode_r);
+ }
+ }
+ }
+
+ break;
+ default:
+ keycode = KEY_UNKNOWN;
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Unsupported event [0x%x]\n", event);
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ break;
+ }
+
+ return;
+}
+
+/* Initialization */
+
static const struct acpi_device_id fujitsu_device_ids[] = {
{ACPI_FUJITSU_HID, 0},
{"", 0},
@@ -251,11 +910,24 @@ static struct acpi_driver acpi_fujitsu_driver = {
},
};
-/* Initialization */
+static const struct acpi_device_id fujitsu_hotkey_device_ids[] = {
+ {ACPI_FUJITSU_HOTKEY_HID, 0},
+ {"", 0},
+};
+
+static struct acpi_driver acpi_fujitsu_hotkey_driver = {
+ .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME,
+ .class = ACPI_FUJITSU_CLASS,
+ .ids = fujitsu_hotkey_device_ids,
+ .ops = {
+ .add = acpi_fujitsu_hotkey_add,
+ .remove = acpi_fujitsu_hotkey_remove,
+ },
+};
static int __init fujitsu_init(void)
{
- int ret, result;
+ int ret, result, max_brightness;
if (acpi_disabled)
return -ENODEV;
@@ -271,19 +943,6 @@ static int __init fujitsu_init(void)
goto fail_acpi;
}
- /* Register backlight stuff */
-
- fujitsu->bl_device =
- backlight_device_register("fujitsu-laptop", NULL, NULL,
- &fujitsubl_ops);
- if (IS_ERR(fujitsu->bl_device))
- return PTR_ERR(fujitsu->bl_device);
-
- fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1;
- ret = platform_driver_register(&fujitsupf_driver);
- if (ret)
- goto fail_backlight;
-
/* Register platform stuff */
fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1);
@@ -302,28 +961,68 @@ static int __init fujitsu_init(void)
if (ret)
goto fail_platform_device2;
+ /* Register backlight stuff */
+
+ fujitsu->bl_device =
+ backlight_device_register("fujitsu-laptop", NULL, NULL,
+ &fujitsubl_ops);
+ if (IS_ERR(fujitsu->bl_device))
+ return PTR_ERR(fujitsu->bl_device);
+
+ max_brightness = fujitsu->max_brightness;
+
+ fujitsu->bl_device->props.max_brightness = max_brightness - 1;
+ fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
+
+ ret = platform_driver_register(&fujitsupf_driver);
+ if (ret)
+ goto fail_backlight;
+
+ /* Register hotkey driver */
+
+ fujitsu_hotkey = kmalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
+ if (!fujitsu_hotkey) {
+ ret = -ENOMEM;
+ goto fail_hotkey;
+ }
+ memset(fujitsu_hotkey, 0, sizeof(struct fujitsu_hotkey_t));
+
+ result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver);
+ if (result < 0) {
+ ret = -ENODEV;
+ goto fail_hotkey1;
+ }
+
printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION
" successfully loaded.\n");
return 0;
- fail_platform_device2:
+fail_hotkey1:
- platform_device_del(fujitsu->pf_device);
-
- fail_platform_device1:
-
- platform_device_put(fujitsu->pf_device);
+ kfree(fujitsu_hotkey);
- fail_platform_driver:
+fail_hotkey:
platform_driver_unregister(&fujitsupf_driver);
- fail_backlight:
+fail_backlight:
backlight_device_unregister(fujitsu->bl_device);
- fail_acpi:
+fail_platform_device2:
+
+ platform_device_del(fujitsu->pf_device);
+
+fail_platform_device1:
+
+ platform_device_put(fujitsu->pf_device);
+
+fail_platform_driver:
+
+ acpi_bus_unregister_driver(&acpi_fujitsu_driver);
+
+fail_acpi:
kfree(fujitsu);
@@ -342,19 +1041,43 @@ static void __exit fujitsu_cleanup(void)
kfree(fujitsu);
+ acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver);
+
+ kfree(fujitsu_hotkey);
+
printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n");
}
module_init(fujitsu_init);
module_exit(fujitsu_cleanup);
-MODULE_AUTHOR("Jonathan Woithe");
+module_param(use_alt_lcd_levels, uint, 0644);
+MODULE_PARM_DESC(use_alt_lcd_levels,
+ "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
+module_param(disable_brightness_keys, uint, 0644);
+MODULE_PARM_DESC(disable_brightness_keys,
+ "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device).");
+module_param(disable_brightness_adjust, uint, 0644);
+MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
+#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
+module_param_named(debug, dbg_level, uint, 0644);
+MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
+#endif
+
+MODULE_AUTHOR("Jonathan Woithe, Peter Gruber");
MODULE_DESCRIPTION("Fujitsu laptop extras support");
MODULE_VERSION(FUJITSU_DRIVER_VERSION);
MODULE_LICENSE("GPL");
+MODULE_ALIAS
+ ("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
+MODULE_ALIAS
+ ("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
+
static struct pnp_device_id pnp_ids[] = {
{ .id = "FUJ02bf" },
+ { .id = "FUJ02B1" },
+ { .id = "FUJ02E3" },
{ .id = "" }
};
MODULE_DEVICE_TABLE(pnp, pnp_ids);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 9d6fc8e6285..dab9d471914 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -293,13 +293,11 @@ EXPORT_SYMBOL(pci_osc_control_set);
* choose highest power _SxD or any lower power
*/
-static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
- pm_message_t state)
+static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
{
int acpi_state;
- acpi_state = acpi_pm_device_sleep_state(&pdev->dev,
- device_may_wakeup(&pdev->dev), NULL);
+ acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL);
if (acpi_state < 0)
return PCI_POWER_ERROR;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e4548ab2a93..75c60239cad 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -508,7 +508,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
return 0;
}
-pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
/**
* pci_choose_state - Choose the power state of a PCI device
@@ -528,7 +528,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
return PCI_D0;
if (platform_pci_choose_state) {
- ret = platform_pci_choose_state(dev, state);
+ ret = platform_pci_choose_state(dev);
if (ret != PCI_POWER_ERROR)
return ret;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 00408c97e5f..312daff834b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -6,8 +6,7 @@ extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
/* Firmware callbacks */
-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev,
- pm_message_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev);
extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
pci_power_t state);
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 886dac823ed..e3fa9a2d9a3 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ */
+
extern spinlock_t pnp_lock;
void *pnp_alloc(long size);
@@ -19,22 +24,118 @@ void pnp_remove_card(struct pnp_card *card);
int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
void pnp_remove_card_device(struct pnp_dev *dev);
-struct pnp_option *pnp_build_option(int priority);
-struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
-struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
- int priority);
-int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_irq *data);
-int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_dma *data);
-int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_port *data);
-int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_mem *data);
+struct pnp_port {
+ resource_size_t min; /* min base number */
+ resource_size_t max; /* max base number */
+ resource_size_t align; /* align boundary */
+ resource_size_t size; /* size of range */
+ unsigned char flags; /* port flags */
+};
+
+#define PNP_IRQ_NR 256
+typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t;
+
+struct pnp_irq {
+ pnp_irq_mask_t map; /* bitmap for IRQ lines */
+ unsigned char flags; /* IRQ flags */
+};
+
+struct pnp_dma {
+ unsigned char map; /* bitmask for DMA channels */
+ unsigned char flags; /* DMA flags */
+};
+
+struct pnp_mem {
+ resource_size_t min; /* min base number */
+ resource_size_t max; /* max base number */
+ resource_size_t align; /* align boundary */
+ resource_size_t size; /* size of range */
+ unsigned char flags; /* memory flags */
+};
+
+#define PNP_OPTION_DEPENDENT 0x80000000
+#define PNP_OPTION_SET_MASK 0xffff
+#define PNP_OPTION_SET_SHIFT 12
+#define PNP_OPTION_PRIORITY_MASK 0xfff
+#define PNP_OPTION_PRIORITY_SHIFT 0
+
+#define PNP_RES_PRIORITY_PREFERRED 0
+#define PNP_RES_PRIORITY_ACCEPTABLE 1
+#define PNP_RES_PRIORITY_FUNCTIONAL 2
+#define PNP_RES_PRIORITY_INVALID PNP_OPTION_PRIORITY_MASK
+
+struct pnp_option {
+ struct list_head list;
+ unsigned int flags; /* independent/dependent, set, priority */
+
+ unsigned long type; /* IORESOURCE_{IO,MEM,IRQ,DMA} */
+ union {
+ struct pnp_port port;
+ struct pnp_irq irq;
+ struct pnp_dma dma;
+ struct pnp_mem mem;
+ } u;
+};
+
+int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
+ pnp_irq_mask_t *map, unsigned char flags);
+int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
+ unsigned char map, unsigned char flags);
+int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
+ resource_size_t min, resource_size_t max,
+ resource_size_t align, resource_size_t size,
+ unsigned char flags);
+int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
+ resource_size_t min, resource_size_t max,
+ resource_size_t align, resource_size_t size,
+ unsigned char flags);
+
+static inline int pnp_option_is_dependent(struct pnp_option *option)
+{
+ return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0;
+}
+
+static inline unsigned int pnp_option_set(struct pnp_option *option)
+{
+ return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK;
+}
+
+static inline unsigned int pnp_option_priority(struct pnp_option *option)
+{
+ return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) &
+ PNP_OPTION_PRIORITY_MASK;
+}
+
+static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev,
+ int priority)
+{
+ unsigned int flags;
+
+ if (priority > PNP_RES_PRIORITY_FUNCTIONAL) {
+ dev_warn(&dev->dev, "invalid dependent option priority %d "
+ "clipped to %d", priority,
+ PNP_RES_PRIORITY_INVALID);
+ priority = PNP_RES_PRIORITY_INVALID;
+ }
+
+ flags = PNP_OPTION_DEPENDENT |
+ ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) <<
+ PNP_OPTION_SET_SHIFT) |
+ ((priority & PNP_OPTION_PRIORITY_MASK) <<
+ PNP_OPTION_PRIORITY_SHIFT);
+
+ dev->num_dependent_sets++;
+
+ return flags;
+}
+
+char *pnp_option_priority_name(struct pnp_option *option);
+void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option);
+
void pnp_init_resources(struct pnp_dev *dev);
void pnp_fixup_device(struct pnp_dev *dev);
-void pnp_free_option(struct pnp_option *option);
+void pnp_free_options(struct pnp_dev *dev);
int __pnp_add_device(struct pnp_dev *dev);
void __pnp_remove_device(struct pnp_dev *dev);
@@ -43,29 +144,18 @@ int pnp_check_mem(struct pnp_dev *dev, struct resource *res);
int pnp_check_irq(struct pnp_dev *dev, struct resource *res);
int pnp_check_dma(struct pnp_dev *dev, struct resource *res);
+char *pnp_resource_type_name(struct resource *res);
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc);
-void pnp_init_resource(struct resource *res);
-
-struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev,
- unsigned int type, unsigned int num);
-
-#define PNP_MAX_PORT 40
-#define PNP_MAX_MEM 24
-#define PNP_MAX_IRQ 2
-#define PNP_MAX_DMA 2
+void pnp_free_resources(struct pnp_dev *dev);
+int pnp_resource_type(struct resource *res);
struct pnp_resource {
+ struct list_head list;
struct resource res;
- unsigned int index; /* ISAPNP config register index */
};
-struct pnp_resource_table {
- struct pnp_resource port[PNP_MAX_PORT];
- struct pnp_resource mem[PNP_MAX_MEM];
- struct pnp_resource dma[PNP_MAX_DMA];
- struct pnp_resource irq[PNP_MAX_IRQ];
-};
+void pnp_free_resource(struct pnp_resource *pnp_res);
struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
int flags);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 20771b7d448..a411582bcd7 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -99,14 +99,28 @@ static void pnp_free_ids(struct pnp_dev *dev)
}
}
+void pnp_free_resource(struct pnp_resource *pnp_res)
+{
+ list_del(&pnp_res->list);
+ kfree(pnp_res);
+}
+
+void pnp_free_resources(struct pnp_dev *dev)
+{
+ struct pnp_resource *pnp_res, *tmp;
+
+ list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
+ pnp_free_resource(pnp_res);
+ }
+}
+
static void pnp_release_device(struct device *dmdev)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
- pnp_free_option(dev->independent);
- pnp_free_option(dev->dependent);
pnp_free_ids(dev);
- kfree(dev->res);
+ pnp_free_resources(dev);
+ pnp_free_options(dev);
kfree(dev);
}
@@ -119,12 +133,8 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid
if (!dev)
return NULL;
- dev->res = kzalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
- if (!dev->res) {
- kfree(dev);
- return NULL;
- }
-
+ INIT_LIST_HEAD(&dev->resources);
+ INIT_LIST_HEAD(&dev->options);
dev->protocol = protocol;
dev->number = id;
dev->dma_mask = DMA_24BIT_MASK;
@@ -140,7 +150,6 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid
dev_id = pnp_add_id(dev, pnpid);
if (!dev_id) {
- kfree(dev->res);
kfree(dev);
return NULL;
}
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 5695a79f3a5..a876ecf7028 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -3,6 +3,8 @@
*
* Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/pnp.h>
@@ -53,11 +55,13 @@ static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
struct pnp_port *port)
{
- pnp_printf(buffer,
- "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
- space, port->min, port->max,
- port->align ? (port->align - 1) : 0, port->size,
- port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
+ pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "
+ "%i-bit address decoding\n", space,
+ (unsigned long long) port->min,
+ (unsigned long long) port->max,
+ port->align ? ((unsigned long long) port->align - 1) : 0,
+ (unsigned long long) port->size,
+ port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
}
static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
@@ -67,7 +71,7 @@ static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
pnp_printf(buffer, "%sirq ", space);
for (i = 0; i < PNP_IRQ_NR; i++)
- if (test_bit(i, irq->map)) {
+ if (test_bit(i, irq->map.bits)) {
if (!first) {
pnp_printf(buffer, ",");
} else {
@@ -78,7 +82,7 @@ static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
else
pnp_printf(buffer, "%i", i);
}
- if (bitmap_empty(irq->map, PNP_IRQ_NR))
+ if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
pnp_printf(buffer, "<none>");
if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
pnp_printf(buffer, " High-Edge");
@@ -88,6 +92,8 @@ static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
pnp_printf(buffer, " High-Level");
if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
pnp_printf(buffer, " Low-Level");
+ if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
+ pnp_printf(buffer, " (optional)");
pnp_printf(buffer, "\n");
}
@@ -148,8 +154,11 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
{
char *s;
- pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
- space, mem->min, mem->max, mem->align, mem->size);
+ pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",
+ space, (unsigned long long) mem->min,
+ (unsigned long long) mem->max,
+ (unsigned long long) mem->align,
+ (unsigned long long) mem->size);
if (mem->flags & IORESOURCE_MEM_WRITEABLE)
pnp_printf(buffer, ", writeable");
if (mem->flags & IORESOURCE_MEM_CACHEABLE)
@@ -177,65 +186,58 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
}
static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
- struct pnp_option *option, int dep)
+ struct pnp_option *option)
{
- char *s;
- struct pnp_port *port;
- struct pnp_irq *irq;
- struct pnp_dma *dma;
- struct pnp_mem *mem;
-
- if (dep) {
- switch (option->priority) {
- case PNP_RES_PRIORITY_PREFERRED:
- s = "preferred";
- break;
- case PNP_RES_PRIORITY_ACCEPTABLE:
- s = "acceptable";
- break;
- case PNP_RES_PRIORITY_FUNCTIONAL:
- s = "functional";
- break;
- default:
- s = "invalid";
- }
- pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
+ switch (option->type) {
+ case IORESOURCE_IO:
+ pnp_print_port(buffer, space, &option->u.port);
+ break;
+ case IORESOURCE_MEM:
+ pnp_print_mem(buffer, space, &option->u.mem);
+ break;
+ case IORESOURCE_IRQ:
+ pnp_print_irq(buffer, space, &option->u.irq);
+ break;
+ case IORESOURCE_DMA:
+ pnp_print_dma(buffer, space, &option->u.dma);
+ break;
}
-
- for (port = option->port; port; port = port->next)
- pnp_print_port(buffer, space, port);
- for (irq = option->irq; irq; irq = irq->next)
- pnp_print_irq(buffer, space, irq);
- for (dma = option->dma; dma; dma = dma->next)
- pnp_print_dma(buffer, space, dma);
- for (mem = option->mem; mem; mem = mem->next)
- pnp_print_mem(buffer, space, mem);
}
static ssize_t pnp_show_options(struct device *dmdev,
struct device_attribute *attr, char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
- struct pnp_option *independent = dev->independent;
- struct pnp_option *dependent = dev->dependent;
- int ret, dep = 1;
+ pnp_info_buffer_t *buffer;
+ struct pnp_option *option;
+ int ret, dep = 0, set = 0;
+ char *indent;
- pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
- pnp_alloc(sizeof(pnp_info_buffer_t));
+ buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
return -ENOMEM;
buffer->len = PAGE_SIZE;
buffer->buffer = buf;
buffer->curr = buffer->buffer;
- if (independent)
- pnp_print_option(buffer, "", independent, 0);
- while (dependent) {
- pnp_print_option(buffer, " ", dependent, dep);
- dependent = dependent->next;
- dep++;
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option)) {
+ indent = " ";
+ if (!dep || pnp_option_set(option) != set) {
+ set = pnp_option_set(option);
+ dep = 1;
+ pnp_printf(buffer, "Dependent: %02i - "
+ "Priority %s\n", set,
+ pnp_option_priority_name(option));
+ }
+ } else {
+ dep = 0;
+ indent = "";
+ }
+ pnp_print_option(buffer, indent, option);
}
+
ret = (buffer->curr - buf);
kfree(buffer);
return ret;
@@ -248,79 +250,59 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
- struct resource *res;
- int i, ret;
pnp_info_buffer_t *buffer;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ int ret;
if (!dev)
return -EINVAL;
- buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t));
+ buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
return -ENOMEM;
+
buffer->len = PAGE_SIZE;
buffer->buffer = buf;
buffer->curr = buffer->buffer;
- pnp_printf(buffer, "state = ");
- if (dev->active)
- pnp_printf(buffer, "active\n");
- else
- pnp_printf(buffer, "disabled\n");
-
- for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
- if (pnp_resource_valid(res)) {
- pnp_printf(buffer, "io");
- if (res->flags & IORESOURCE_DISABLED)
- pnp_printf(buffer, " disabled\n");
- else
- pnp_printf(buffer, " 0x%llx-0x%llx\n",
- (unsigned long long) res->start,
- (unsigned long long) res->end);
- }
- }
- for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
- if (pnp_resource_valid(res)) {
- pnp_printf(buffer, "mem");
- if (res->flags & IORESOURCE_DISABLED)
- pnp_printf(buffer, " disabled\n");
- else
- pnp_printf(buffer, " 0x%llx-0x%llx\n",
- (unsigned long long) res->start,
- (unsigned long long) res->end);
- }
- }
- for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
- if (pnp_resource_valid(res)) {
- pnp_printf(buffer, "irq");
- if (res->flags & IORESOURCE_DISABLED)
- pnp_printf(buffer, " disabled\n");
- else
- pnp_printf(buffer, " %lld\n",
- (unsigned long long) res->start);
+ pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");
+
+ list_for_each_entry(pnp_res, &dev->resources, list) {
+ res = &pnp_res->res;
+
+ pnp_printf(buffer, pnp_resource_type_name(res));
+
+ if (res->flags & IORESOURCE_DISABLED) {
+ pnp_printf(buffer, " disabled\n");
+ continue;
}
- }
- for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
- if (pnp_resource_valid(res)) {
- pnp_printf(buffer, "dma");
- if (res->flags & IORESOURCE_DISABLED)
- pnp_printf(buffer, " disabled\n");
- else
- pnp_printf(buffer, " %lld\n",
- (unsigned long long) res->start);
+
+ switch (pnp_resource_type(res)) {
+ case IORESOURCE_IO:
+ case IORESOURCE_MEM:
+ pnp_printf(buffer, " %#llx-%#llx\n",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end);
+ break;
+ case IORESOURCE_IRQ:
+ case IORESOURCE_DMA:
+ pnp_printf(buffer, " %lld\n",
+ (unsigned long long) res->start);
+ break;
}
}
+
ret = (buffer->curr - buf);
kfree(buffer);
return ret;
}
-static ssize_t
-pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
- const char *ubuf, size_t count)
+static ssize_t pnp_set_current_resources(struct device *dmdev,
+ struct device_attribute *attr,
+ const char *ubuf, size_t count)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
- struct pnp_resource *pnp_res;
char *buf = (void *)ubuf;
int retval = 0;
resource_size_t start, end;
@@ -368,7 +350,6 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
goto done;
}
if (!strnicmp(buf, "set", 3)) {
- int nport = 0, nmem = 0, nirq = 0, ndma = 0;
if (dev->active)
goto done;
buf += 3;
@@ -391,10 +372,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
end = simple_strtoul(buf, &buf, 0);
} else
end = start;
- pnp_res = pnp_add_io_resource(dev, start, end,
- 0);
- if (pnp_res)
- pnp_res->index = nport++;
+ pnp_add_io_resource(dev, start, end, 0);
continue;
}
if (!strnicmp(buf, "mem", 3)) {
@@ -411,10 +389,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
end = simple_strtoul(buf, &buf, 0);
} else
end = start;
- pnp_res = pnp_add_mem_resource(dev, start, end,
- 0);
- if (pnp_res)
- pnp_res->index = nmem++;
+ pnp_add_mem_resource(dev, start, end, 0);
continue;
}
if (!strnicmp(buf, "irq", 3)) {
@@ -422,9 +397,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
while (isspace(*buf))
++buf;
start = simple_strtoul(buf, &buf, 0);
- pnp_res = pnp_add_irq_resource(dev, start, 0);
- if (pnp_res)
- pnp_res->index = nirq++;
+ pnp_add_irq_resource(dev, start, 0);
continue;
}
if (!strnicmp(buf, "dma", 3)) {
@@ -432,9 +405,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
while (isspace(*buf))
++buf;
start = simple_strtoul(buf, &buf, 0);
- pnp_res = pnp_add_dma_resource(dev, start, 0);
- if (pnp_res)
- pnp_res->index = ndma++;
+ pnp_add_dma_resource(dev, start, 0);
continue;
}
break;
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index f1bccdbdeb0..101a835e875 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -429,154 +429,135 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
* Add IRQ resource to resources list.
*/
static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[3];
- struct pnp_irq *irq;
unsigned long bits;
+ pnp_irq_mask_t map;
+ unsigned char flags = IORESOURCE_IRQ_HIGHEDGE;
isapnp_peek(tmp, size);
- irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
- if (!irq)
- return;
bits = (tmp[1] << 8) | tmp[0];
- bitmap_copy(irq->map, &bits, 16);
+
+ bitmap_zero(map.bits, PNP_IRQ_NR);
+ bitmap_copy(map.bits, &bits, 16);
+
if (size > 2)
- irq->flags = tmp[2];
- else
- irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(dev, option, irq);
+ flags = tmp[2];
+
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
/*
* Add DMA resource to resources list.
*/
static void __init isapnp_parse_dma_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[2];
- struct pnp_dma *dma;
isapnp_peek(tmp, size);
- dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
- if (!dma)
- return;
- dma->map = tmp[0];
- dma->flags = tmp[1];
- pnp_register_dma_resource(dev, option, dma);
+ pnp_register_dma_resource(dev, option_flags, tmp[0], tmp[1]);
}
/*
* Add port resource to resources list.
*/
static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[7];
- struct pnp_port *port;
+ resource_size_t min, max, align, len;
+ unsigned char flags;
isapnp_peek(tmp, size);
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = (tmp[2] << 8) | tmp[1];
- port->max = (tmp[4] << 8) | tmp[3];
- port->align = tmp[5];
- port->size = tmp[6];
- port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(dev, option, port);
+ min = (tmp[2] << 8) | tmp[1];
+ max = (tmp[4] << 8) | tmp[3];
+ align = tmp[5];
+ len = tmp[6];
+ flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0;
+ pnp_register_port_resource(dev, option_flags,
+ min, max, align, len, flags);
}
/*
* Add fixed port resource to resources list.
*/
static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[3];
- struct pnp_port *port;
+ resource_size_t base, len;
isapnp_peek(tmp, size);
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = port->max = (tmp[1] << 8) | tmp[0];
- port->size = tmp[2];
- port->align = 0;
- port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(dev, option, port);
+ base = (tmp[1] << 8) | tmp[0];
+ len = tmp[2];
+ pnp_register_port_resource(dev, option_flags, base, base, 0, len,
+ IORESOURCE_IO_FIXED);
}
/*
* Add memory resource to resources list.
*/
static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[9];
- struct pnp_mem *mem;
+ resource_size_t min, max, align, len;
+ unsigned char flags;
isapnp_peek(tmp, size);
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
- mem->max = ((tmp[4] << 8) | tmp[3]) << 8;
- mem->align = (tmp[6] << 8) | tmp[5];
- mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
- mem->flags = tmp[0];
- pnp_register_mem_resource(dev, option, mem);
+ min = ((tmp[2] << 8) | tmp[1]) << 8;
+ max = ((tmp[4] << 8) | tmp[3]) << 8;
+ align = (tmp[6] << 8) | tmp[5];
+ len = ((tmp[8] << 8) | tmp[7]) << 8;
+ flags = tmp[0];
+ pnp_register_mem_resource(dev, option_flags,
+ min, max, align, len, flags);
}
/*
* Add 32-bit memory resource to resources list.
*/
static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[17];
- struct pnp_mem *mem;
+ resource_size_t min, max, align, len;
+ unsigned char flags;
isapnp_peek(tmp, size);
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
- mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
- mem->align =
- (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
- mem->size =
- (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
- mem->flags = tmp[0];
- pnp_register_mem_resource(dev, option, mem);
+ min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
+ max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
+ align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
+ len = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
+ flags = tmp[0];
+ pnp_register_mem_resource(dev, option_flags,
+ min, max, align, len, flags);
}
/*
* Add 32-bit fixed memory resource to resources list.
*/
static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[9];
- struct pnp_mem *mem;
+ resource_size_t base, len;
+ unsigned char flags;
isapnp_peek(tmp, size);
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = mem->max =
- (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
- mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
- mem->align = 0;
- mem->flags = tmp[0];
- pnp_register_mem_resource(dev, option, mem);
+ base = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
+ len = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
+ flags = tmp[0];
+ pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
}
/*
@@ -604,20 +585,16 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
static int __init isapnp_create_device(struct pnp_card *card,
unsigned short size)
{
- int number = 0, skip = 0, priority = 0, compat = 0;
+ int number = 0, skip = 0, priority, compat = 0;
unsigned char type, tmp[17];
- struct pnp_option *option;
+ unsigned int option_flags;
struct pnp_dev *dev;
u32 eisa_id;
char id[8];
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
- option = pnp_register_independent_option(dev);
- if (!option) {
- kfree(dev);
- return 1;
- }
+ option_flags = 0;
pnp_add_card_device(card, dev);
while (1) {
@@ -634,16 +611,11 @@ static int __init isapnp_create_device(struct pnp_card *card,
return 1;
size = 0;
skip = 0;
- option = pnp_register_independent_option(dev);
- if (!option) {
- kfree(dev);
- return 1;
- }
+ option_flags = 0;
pnp_add_card_device(card, dev);
} else {
skip = 1;
}
- priority = 0;
compat = 0;
break;
case _STAG_COMPATDEVID:
@@ -660,44 +632,42 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _STAG_IRQ:
if (size < 2 || size > 3)
goto __skip;
- isapnp_parse_irq_resource(dev, option, size);
+ isapnp_parse_irq_resource(dev, option_flags, size);
size = 0;
break;
case _STAG_DMA:
if (size != 2)
goto __skip;
- isapnp_parse_dma_resource(dev, option, size);
+ isapnp_parse_dma_resource(dev, option_flags, size);
size = 0;
break;
case _STAG_STARTDEP:
if (size > 1)
goto __skip;
- priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
+ priority = PNP_RES_PRIORITY_ACCEPTABLE;
if (size > 0) {
isapnp_peek(tmp, size);
- priority = 0x100 | tmp[0];
+ priority = tmp[0];
size = 0;
}
- option = pnp_register_dependent_option(dev, priority);
- if (!option)
- return 1;
+ option_flags = pnp_new_dependent_set(dev, priority);
break;
case _STAG_ENDDEP:
if (size != 0)
goto __skip;
- priority = 0;
- dev_dbg(&dev->dev, "end dependent options\n");
+ option_flags = 0;
break;
case _STAG_IOPORT:
if (size != 7)
goto __skip;
- isapnp_parse_port_resource(dev, option, size);
+ isapnp_parse_port_resource(dev, option_flags, size);
size = 0;
break;
case _STAG_FIXEDIO:
if (size != 3)
goto __skip;
- isapnp_parse_fixed_port_resource(dev, option, size);
+ isapnp_parse_fixed_port_resource(dev, option_flags,
+ size);
size = 0;
break;
case _STAG_VENDOR:
@@ -705,7 +675,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEMRANGE:
if (size != 9)
goto __skip;
- isapnp_parse_mem_resource(dev, option, size);
+ isapnp_parse_mem_resource(dev, option_flags, size);
size = 0;
break;
case _LTAG_ANSISTR:
@@ -720,13 +690,14 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEM32RANGE:
if (size != 17)
goto __skip;
- isapnp_parse_mem32_resource(dev, option, size);
+ isapnp_parse_mem32_resource(dev, option_flags, size);
size = 0;
break;
case _LTAG_FIXEDMEM32RANGE:
if (size != 9)
goto __skip;
- isapnp_parse_fixed_mem32_resource(dev, option, size);
+ isapnp_parse_fixed_mem32_resource(dev, option_flags,
+ size);
size = 0;
break;
case _STAG_END:
@@ -928,7 +899,6 @@ EXPORT_SYMBOL(isapnp_write_byte);
static int isapnp_get_resources(struct pnp_dev *dev)
{
- struct pnp_resource *pnp_res;
int i, ret;
dev_dbg(&dev->dev, "get resources\n");
@@ -940,35 +910,23 @@ static int isapnp_get_resources(struct pnp_dev *dev)
for (i = 0; i < ISAPNP_MAX_PORT; i++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
- if (ret) {
- pnp_res = pnp_add_io_resource(dev, ret, ret, 0);
- if (pnp_res)
- pnp_res->index = i;
- }
+ pnp_add_io_resource(dev, ret, ret,
+ ret == 0 ? IORESOURCE_DISABLED : 0);
}
for (i = 0; i < ISAPNP_MAX_MEM; i++) {
ret = isapnp_read_word(ISAPNP_CFG_MEM + (i << 3)) << 8;
- if (ret) {
- pnp_res = pnp_add_mem_resource(dev, ret, ret, 0);
- if (pnp_res)
- pnp_res->index = i;
- }
+ pnp_add_mem_resource(dev, ret, ret,
+ ret == 0 ? IORESOURCE_DISABLED : 0);
}
for (i = 0; i < ISAPNP_MAX_IRQ; i++) {
ret = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)) >> 8;
- if (ret) {
- pnp_res = pnp_add_irq_resource(dev, ret, 0);
- if (pnp_res)
- pnp_res->index = i;
- }
+ pnp_add_irq_resource(dev, ret,
+ ret == 0 ? IORESOURCE_DISABLED : 0);
}
for (i = 0; i < ISAPNP_MAX_DMA; i++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + i);
- if (ret != 4) {
- pnp_res = pnp_add_dma_resource(dev, ret, 0);
- if (pnp_res)
- pnp_res->index = i;
- }
+ pnp_add_dma_resource(dev, ret,
+ ret == 4 ? IORESOURCE_DISABLED : 0);
}
__end:
@@ -978,62 +936,45 @@ __end:
static int isapnp_set_resources(struct pnp_dev *dev)
{
- struct pnp_resource *pnp_res;
struct resource *res;
- int tmp, index;
+ int tmp;
dev_dbg(&dev->dev, "set resources\n");
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, tmp);
- if (!pnp_res)
- continue;
- res = &pnp_res->res;
- if (pnp_resource_valid(res)) {
- index = pnp_res->index;
+ res = pnp_get_resource(dev, IORESOURCE_IO, tmp);
+ if (pnp_resource_enabled(res)) {
dev_dbg(&dev->dev, " set io %d to %#llx\n",
- index, (unsigned long long) res->start);
- isapnp_write_word(ISAPNP_CFG_PORT + (index << 1),
+ tmp, (unsigned long long) res->start);
+ isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
res->start);
}
}
for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, tmp);
- if (!pnp_res)
- continue;
- res = &pnp_res->res;
- if (pnp_resource_valid(res)) {
+ res = pnp_get_resource(dev, IORESOURCE_IRQ, tmp);
+ if (pnp_resource_enabled(res)) {
int irq = res->start;
if (irq == 2)
irq = 9;
- index = pnp_res->index;
- dev_dbg(&dev->dev, " set irq %d to %d\n", index, irq);
- isapnp_write_byte(ISAPNP_CFG_IRQ + (index << 1), irq);
+ dev_dbg(&dev->dev, " set irq %d to %d\n", tmp, irq);
+ isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
}
}
for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, tmp);
- if (!pnp_res)
- continue;
- res = &pnp_res->res;
- if (pnp_resource_valid(res)) {
- index = pnp_res->index;
+ res = pnp_get_resource(dev, IORESOURCE_DMA, tmp);
+ if (pnp_resource_enabled(res)) {
dev_dbg(&dev->dev, " set dma %d to %lld\n",
- index, (unsigned long long) res->start);
- isapnp_write_byte(ISAPNP_CFG_DMA + index, res->start);
+ tmp, (unsigned long long) res->start);
+ isapnp_write_byte(ISAPNP_CFG_DMA + tmp, res->start);
}
}
for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, tmp);
- if (!pnp_res)
- continue;
- res = &pnp_res->res;
- if (pnp_resource_valid(res)) {
- index = pnp_res->index;
+ res = pnp_get_resource(dev, IORESOURCE_MEM, tmp);
+ if (pnp_resource_enabled(res)) {
dev_dbg(&dev->dev, " set mem %d to %#llx\n",
- index, (unsigned long long) res->start);
- isapnp_write_word(ISAPNP_CFG_MEM + (index << 3),
+ tmp, (unsigned long long) res->start);
+ isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
(res->start >> 8) & 0xffff);
}
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index bea0914ff94..b526eaad3f6 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -3,6 +3,8 @@
*
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/errno.h>
@@ -19,82 +21,64 @@ DEFINE_MUTEX(pnp_res_mutex);
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
- struct pnp_resource *pnp_res;
- struct resource *res;
-
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, idx);
- if (!pnp_res) {
- dev_err(&dev->dev, "too many I/O port resources\n");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
- }
-
- res = &pnp_res->res;
+ struct resource *res, local_res;
- /* check if this resource has been manually set, if so skip */
- if (!(res->flags & IORESOURCE_AUTO)) {
+ res = pnp_get_resource(dev, IORESOURCE_IO, idx);
+ if (res) {
dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx "
"flags %#lx\n", idx, (unsigned long long) res->start,
(unsigned long long) res->end, res->flags);
- return 1;
+ return 0;
}
- /* set the initial values */
- pnp_res->index = idx;
- res->flags |= rule->flags | IORESOURCE_IO;
- res->flags &= ~IORESOURCE_UNSET;
+ res = &local_res;
+ res->flags = rule->flags | IORESOURCE_AUTO;
+ res->start = 0;
+ res->end = 0;
if (!rule->size) {
res->flags |= IORESOURCE_DISABLED;
dev_dbg(&dev->dev, " io %d disabled\n", idx);
- return 1; /* skip disabled resource requests */
+ goto __add;
}
res->start = rule->min;
res->end = res->start + rule->size - 1;
- /* run through until pnp_check_port is happy */
while (!pnp_check_port(dev, res)) {
res->start += rule->align;
res->end = res->start + rule->size - 1;
if (res->start > rule->max || !rule->align) {
- dev_dbg(&dev->dev, " couldn't assign io %d\n", idx);
- return 0;
+ dev_dbg(&dev->dev, " couldn't assign io %d "
+ "(min %#llx max %#llx)\n", idx,
+ (unsigned long long) rule->min,
+ (unsigned long long) rule->max);
+ return -EBUSY;
}
}
- dev_dbg(&dev->dev, " assign io %d %#llx-%#llx\n", idx,
- (unsigned long long) res->start, (unsigned long long) res->end);
- return 1;
+
+__add:
+ pnp_add_io_resource(dev, res->start, res->end, res->flags);
+ return 0;
}
static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
- struct pnp_resource *pnp_res;
- struct resource *res;
-
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, idx);
- if (!pnp_res) {
- dev_err(&dev->dev, "too many memory resources\n");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
- }
+ struct resource *res, local_res;
- res = &pnp_res->res;
-
- /* check if this resource has been manually set, if so skip */
- if (!(res->flags & IORESOURCE_AUTO)) {
+ res = pnp_get_resource(dev, IORESOURCE_MEM, idx);
+ if (res) {
dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx "
"flags %#lx\n", idx, (unsigned long long) res->start,
(unsigned long long) res->end, res->flags);
- return 1;
+ return 0;
}
- /* set the initial values */
- pnp_res->index = idx;
- res->flags |= rule->flags | IORESOURCE_MEM;
- res->flags &= ~IORESOURCE_UNSET;
+ res = &local_res;
+ res->flags = rule->flags | IORESOURCE_AUTO;
+ res->start = 0;
+ res->end = 0;
- /* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
res->flags |= IORESOURCE_READONLY;
if (rule->flags & IORESOURCE_MEM_CACHEABLE)
@@ -107,30 +91,32 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
if (!rule->size) {
res->flags |= IORESOURCE_DISABLED;
dev_dbg(&dev->dev, " mem %d disabled\n", idx);
- return 1; /* skip disabled resource requests */
+ goto __add;
}
res->start = rule->min;
res->end = res->start + rule->size - 1;
- /* run through until pnp_check_mem is happy */
while (!pnp_check_mem(dev, res)) {
res->start += rule->align;
res->end = res->start + rule->size - 1;
if (res->start > rule->max || !rule->align) {
- dev_dbg(&dev->dev, " couldn't assign mem %d\n", idx);
- return 0;
+ dev_dbg(&dev->dev, " couldn't assign mem %d "
+ "(min %#llx max %#llx)\n", idx,
+ (unsigned long long) rule->min,
+ (unsigned long long) rule->max);
+ return -EBUSY;
}
}
- dev_dbg(&dev->dev, " assign mem %d %#llx-%#llx\n", idx,
- (unsigned long long) res->start, (unsigned long long) res->end);
- return 1;
+
+__add:
+ pnp_add_mem_resource(dev, res->start, res->end, res->flags);
+ return 0;
}
static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
{
- struct pnp_resource *pnp_res;
- struct resource *res;
+ struct resource *res, local_res;
int i;
/* IRQ priority: this table is good for i386 */
@@ -138,59 +124,57 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, idx);
- if (!pnp_res) {
- dev_err(&dev->dev, "too many IRQ resources\n");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
- }
-
- res = &pnp_res->res;
-
- /* check if this resource has been manually set, if so skip */
- if (!(res->flags & IORESOURCE_AUTO)) {
+ res = pnp_get_resource(dev, IORESOURCE_IRQ, idx);
+ if (res) {
dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n",
idx, (int) res->start, res->flags);
- return 1;
+ return 0;
}
- /* set the initial values */
- pnp_res->index = idx;
- res->flags |= rule->flags | IORESOURCE_IRQ;
- res->flags &= ~IORESOURCE_UNSET;
+ res = &local_res;
+ res->flags = rule->flags | IORESOURCE_AUTO;
+ res->start = -1;
+ res->end = -1;
- if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
+ if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
res->flags |= IORESOURCE_DISABLED;
dev_dbg(&dev->dev, " irq %d disabled\n", idx);
- return 1; /* skip disabled resource requests */
+ goto __add;
}
/* TBD: need check for >16 IRQ */
- res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+ res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
if (res->start < PNP_IRQ_NR) {
res->end = res->start;
- dev_dbg(&dev->dev, " assign irq %d %d\n", idx,
- (int) res->start);
- return 1;
+ goto __add;
}
for (i = 0; i < 16; i++) {
- if (test_bit(xtab[i], rule->map)) {
+ if (test_bit(xtab[i], rule->map.bits)) {
res->start = res->end = xtab[i];
- if (pnp_check_irq(dev, res)) {
- dev_dbg(&dev->dev, " assign irq %d %d\n", idx,
- (int) res->start);
- return 1;
- }
+ if (pnp_check_irq(dev, res))
+ goto __add;
}
}
+
+ if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
+ res->start = -1;
+ res->end = -1;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " irq %d disabled (optional)\n", idx);
+ goto __add;
+ }
+
dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
+ return -EBUSY;
+
+__add:
+ pnp_add_irq_resource(dev, res->start, res->flags);
return 0;
}
-static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
+static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
- struct pnp_resource *pnp_res;
- struct resource *res;
+ struct resource *res, local_res;
int i;
/* DMA priority: this table is good for i386 */
@@ -198,231 +182,99 @@ static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1, 3, 5, 6, 7, 0, 2, 4
};
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, idx);
- if (!pnp_res) {
- dev_err(&dev->dev, "too many DMA resources\n");
- return;
- }
-
- res = &pnp_res->res;
-
- /* check if this resource has been manually set, if so skip */
- if (!(res->flags & IORESOURCE_AUTO)) {
+ res = pnp_get_resource(dev, IORESOURCE_DMA, idx);
+ if (res) {
dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n",
idx, (int) res->start, res->flags);
- return;
+ return 0;
}
- /* set the initial values */
- pnp_res->index = idx;
- res->flags |= rule->flags | IORESOURCE_DMA;
- res->flags &= ~IORESOURCE_UNSET;
+ res = &local_res;
+ res->flags = rule->flags | IORESOURCE_AUTO;
+ res->start = -1;
+ res->end = -1;
for (i = 0; i < 8; i++) {
if (rule->map & (1 << xtab[i])) {
res->start = res->end = xtab[i];
- if (pnp_check_dma(dev, res)) {
- dev_dbg(&dev->dev, " assign dma %d %d\n", idx,
- (int) res->start);
- return;
- }
+ if (pnp_check_dma(dev, res))
+ goto __add;
}
}
#ifdef MAX_DMA_CHANNELS
res->start = res->end = MAX_DMA_CHANNELS;
#endif
- res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
dev_dbg(&dev->dev, " disable dma %d\n", idx);
-}
-
-void pnp_init_resource(struct resource *res)
-{
- unsigned long type;
-
- type = res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
- IORESOURCE_IRQ | IORESOURCE_DMA);
- res->name = NULL;
- res->flags = type | IORESOURCE_AUTO | IORESOURCE_UNSET;
- if (type == IORESOURCE_IRQ || type == IORESOURCE_DMA) {
- res->start = -1;
- res->end = -1;
- } else {
- res->start = 0;
- res->end = 0;
- }
+__add:
+ pnp_add_dma_resource(dev, res->start, res->flags);
+ return 0;
}
-/**
- * pnp_init_resources - Resets a resource table to default values.
- * @table: pointer to the desired resource table
- */
void pnp_init_resources(struct pnp_dev *dev)
{
- struct resource *res;
- int idx;
-
- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
- res = &dev->res->irq[idx].res;
- res->flags = IORESOURCE_IRQ;
- pnp_init_resource(res);
- }
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
- res = &dev->res->dma[idx].res;
- res->flags = IORESOURCE_DMA;
- pnp_init_resource(res);
- }
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
- res = &dev->res->port[idx].res;
- res->flags = IORESOURCE_IO;
- pnp_init_resource(res);
- }
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
- res = &dev->res->mem[idx].res;
- res->flags = IORESOURCE_MEM;
- pnp_init_resource(res);
- }
+ pnp_free_resources(dev);
}
-/**
- * pnp_clean_resources - clears resources that were not manually set
- * @res: the resources to clean
- */
static void pnp_clean_resource_table(struct pnp_dev *dev)
{
- struct resource *res;
- int idx;
-
- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
- res = &dev->res->irq[idx].res;
- if (res->flags & IORESOURCE_AUTO) {
- res->flags = IORESOURCE_IRQ;
- pnp_init_resource(res);
- }
- }
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
- res = &dev->res->dma[idx].res;
- if (res->flags & IORESOURCE_AUTO) {
- res->flags = IORESOURCE_DMA;
- pnp_init_resource(res);
- }
- }
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
- res = &dev->res->port[idx].res;
- if (res->flags & IORESOURCE_AUTO) {
- res->flags = IORESOURCE_IO;
- pnp_init_resource(res);
- }
- }
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
- res = &dev->res->mem[idx].res;
- if (res->flags & IORESOURCE_AUTO) {
- res->flags = IORESOURCE_MEM;
- pnp_init_resource(res);
- }
+ struct pnp_resource *pnp_res, *tmp;
+
+ list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
+ if (pnp_res->res.flags & IORESOURCE_AUTO)
+ pnp_free_resource(pnp_res);
}
}
/**
* pnp_assign_resources - assigns resources to the device based on the specified dependent number
* @dev: pointer to the desired device
- * @depnum: the dependent function number
- *
- * Only set depnum to 0 if the device does not have dependent options.
+ * @set: the dependent function number
*/
-static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
+static int pnp_assign_resources(struct pnp_dev *dev, int set)
{
- struct pnp_port *port;
- struct pnp_mem *mem;
- struct pnp_irq *irq;
- struct pnp_dma *dma;
+ struct pnp_option *option;
int nport = 0, nmem = 0, nirq = 0, ndma = 0;
+ int ret = 0;
- if (!pnp_can_configure(dev))
- return -ENODEV;
-
- dbg_pnp_show_resources(dev, "before pnp_assign_resources");
+ dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(dev);
- if (dev->independent) {
- dev_dbg(&dev->dev, "assigning independent options\n");
- port = dev->independent->port;
- mem = dev->independent->mem;
- irq = dev->independent->irq;
- dma = dev->independent->dma;
- while (port) {
- if (!pnp_assign_port(dev, port, nport))
- goto fail;
- nport++;
- port = port->next;
- }
- while (mem) {
- if (!pnp_assign_mem(dev, mem, nmem))
- goto fail;
- nmem++;
- mem = mem->next;
- }
- while (irq) {
- if (!pnp_assign_irq(dev, irq, nirq))
- goto fail;
- nirq++;
- irq = irq->next;
- }
- while (dma) {
- pnp_assign_dma(dev, dma, ndma);
- ndma++;
- dma = dma->next;
- }
- }
- if (depnum) {
- struct pnp_option *dep;
- int i;
-
- dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
- for (i = 1, dep = dev->dependent; i < depnum;
- i++, dep = dep->next)
- if (!dep)
- goto fail;
- port = dep->port;
- mem = dep->mem;
- irq = dep->irq;
- dma = dep->dma;
- while (port) {
- if (!pnp_assign_port(dev, port, nport))
- goto fail;
- nport++;
- port = port->next;
- }
- while (mem) {
- if (!pnp_assign_mem(dev, mem, nmem))
- goto fail;
- nmem++;
- mem = mem->next;
- }
- while (irq) {
- if (!pnp_assign_irq(dev, irq, nirq))
- goto fail;
- nirq++;
- irq = irq->next;
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option) &&
+ pnp_option_set(option) != set)
+ continue;
+
+ switch (option->type) {
+ case IORESOURCE_IO:
+ ret = pnp_assign_port(dev, &option->u.port, nport++);
+ break;
+ case IORESOURCE_MEM:
+ ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
+ break;
+ case IORESOURCE_IRQ:
+ ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
+ break;
+ case IORESOURCE_DMA:
+ ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- while (dma) {
- pnp_assign_dma(dev, dma, ndma);
- ndma++;
- dma = dma->next;
- }
- } else if (dev->dependent)
- goto fail;
-
- mutex_unlock(&pnp_res_mutex);
- dbg_pnp_show_resources(dev, "after pnp_assign_resources");
- return 1;
+ if (ret < 0)
+ break;
+ }
-fail:
- pnp_clean_resource_table(dev);
mutex_unlock(&pnp_res_mutex);
- dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
- return 0;
+ if (ret < 0) {
+ dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
+ pnp_clean_resource_table(dev);
+ } else
+ dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
+ return ret;
}
/**
@@ -431,29 +283,25 @@ fail:
*/
int pnp_auto_config_dev(struct pnp_dev *dev)
{
- struct pnp_option *dep;
- int i = 1;
+ int i, ret;
if (!pnp_can_configure(dev)) {
dev_dbg(&dev->dev, "configuration not supported\n");
return -ENODEV;
}
- if (!dev->dependent) {
- if (pnp_assign_resources(dev, 0))
+ ret = pnp_assign_resources(dev, 0);
+ if (ret == 0)
+ return 0;
+
+ for (i = 1; i < dev->num_dependent_sets; i++) {
+ ret = pnp_assign_resources(dev, i);
+ if (ret == 0)
return 0;
- } else {
- dep = dev->dependent;
- do {
- if (pnp_assign_resources(dev, i))
- return 0;
- dep = dep->next;
- i++;
- } while (dep);
}
dev_err(&dev->dev, "unable to assign resources\n");
- return -EBUSY;
+ return ret;
}
/**
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 50902773bea..c1b9ea34977 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -117,9 +117,7 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
{
int power_state;
- power_state = acpi_pm_device_sleep_state(&dev->dev,
- device_may_wakeup(&dev->dev),
- NULL);
+ power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
if (power_state < 0)
power_state = (state.event == PM_EVENT_ON) ?
ACPI_STATE_D0 : ACPI_STATE_D3;
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 46c791adb89..d7e9f2152df 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -3,6 +3,8 @@
*
* Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
* Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -98,8 +100,10 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
int irq, flags;
int p, t;
- if (!valid_IRQ(gsi))
+ if (!valid_IRQ(gsi)) {
+ pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED);
return;
+ }
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
@@ -178,13 +182,68 @@ static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
u64 end = start + len - 1;
if (io_decode == ACPI_DECODE_16)
- flags |= PNP_PORT_FLAG_16BITADDR;
+ flags |= IORESOURCE_IO_16BIT_ADDR;
if (len == 0 || end >= 0x10003)
flags |= IORESOURCE_DISABLED;
pnp_add_io_resource(dev, start, end, flags);
}
+/*
+ * Device CSRs that do not appear in PCI config space should be described
+ * via ACPI. This would normally be done with Address Space Descriptors
+ * marked as "consumer-only," but old versions of Windows and Linux ignore
+ * the producer/consumer flag, so HP invented a vendor-defined resource to
+ * describe the location and size of CSR space.
+ */
+static struct acpi_vendor_uuid hp_ccsr_uuid = {
+ .subtype = 2,
+ .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a,
+ 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad },
+};
+
+static int vendor_resource_matches(struct pnp_dev *dev,
+ struct acpi_resource_vendor_typed *vendor,
+ struct acpi_vendor_uuid *match,
+ int expected_len)
+{
+ int uuid_len = sizeof(vendor->uuid);
+ u8 uuid_subtype = vendor->uuid_subtype;
+ u8 *uuid = vendor->uuid;
+ int actual_len;
+
+ /* byte_length includes uuid_subtype and uuid */
+ actual_len = vendor->byte_length - uuid_len - 1;
+
+ if (uuid_subtype == match->subtype &&
+ uuid_len == sizeof(match->data) &&
+ memcmp(uuid, match->data, uuid_len) == 0) {
+ if (expected_len && expected_len != actual_len) {
+ dev_err(&dev->dev, "wrong vendor descriptor size; "
+ "expected %d, found %d bytes\n",
+ expected_len, actual_len);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
+ struct acpi_resource_vendor_typed *vendor)
+{
+ if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) {
+ u64 start, length;
+
+ memcpy(&start, vendor->byte_data, sizeof(start));
+ memcpy(&length, vendor->byte_data + 8, sizeof(length));
+
+ pnp_add_mem_resource(dev, start, start + length - 1, 0);
+ }
+}
+
static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
u64 start, u64 len,
int write_protect)
@@ -235,6 +294,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
struct acpi_resource_dma *dma;
struct acpi_resource_io *io;
struct acpi_resource_fixed_io *fixed_io;
+ struct acpi_resource_vendor_typed *vendor_typed;
struct acpi_resource_memory24 *memory24;
struct acpi_resource_memory32 *memory32;
struct acpi_resource_fixed_memory32 *fixed_memory32;
@@ -248,24 +308,39 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
* _CRS, but some firmware violates this, so parse them all.
*/
irq = &res->data.irq;
- for (i = 0; i < irq->interrupt_count; i++) {
- pnpacpi_parse_allocated_irqresource(dev,
- irq->interrupts[i],
- irq->triggering,
- irq->polarity,
- irq->sharable);
+ if (irq->interrupt_count == 0)
+ pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
+ else {
+ for (i = 0; i < irq->interrupt_count; i++) {
+ pnpacpi_parse_allocated_irqresource(dev,
+ irq->interrupts[i],
+ irq->triggering,
+ irq->polarity,
+ irq->sharable);
+ }
+
+ /*
+ * The IRQ encoder puts a single interrupt in each
+ * descriptor, so if a _CRS descriptor has more than
+ * one interrupt, we won't be able to re-encode it.
+ */
+ if (pnp_can_write(dev) && irq->interrupt_count > 1) {
+ dev_warn(&dev->dev, "multiple interrupts in "
+ "_CRS descriptor; configuration can't "
+ "be changed\n");
+ dev->capabilities &= ~PNP_WRITE;
+ }
}
break;
case ACPI_RESOURCE_TYPE_DMA:
dma = &res->data.dma;
- if (dma->channel_count > 0) {
+ if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
flags = dma_flags(dma->type, dma->bus_master,
dma->transfer);
- if (dma->channels[0] == (u8) -1)
- flags |= IORESOURCE_DISABLED;
- pnp_add_dma_resource(dev, dma->channels[0], flags);
- }
+ else
+ flags = IORESOURCE_DISABLED;
+ pnp_add_dma_resource(dev, dma->channels[0], flags);
break;
case ACPI_RESOURCE_TYPE_IO:
@@ -289,6 +364,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_VENDOR:
+ vendor_typed = &res->data.vendor_typed;
+ pnpacpi_parse_allocated_vendor(dev, vendor_typed);
break;
case ACPI_RESOURCE_TYPE_END_TAG:
@@ -331,12 +408,29 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
if (extended_irq->producer_consumer == ACPI_PRODUCER)
return AE_OK;
- for (i = 0; i < extended_irq->interrupt_count; i++) {
- pnpacpi_parse_allocated_irqresource(dev,
- extended_irq->interrupts[i],
- extended_irq->triggering,
- extended_irq->polarity,
- extended_irq->sharable);
+ if (extended_irq->interrupt_count == 0)
+ pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
+ else {
+ for (i = 0; i < extended_irq->interrupt_count; i++) {
+ pnpacpi_parse_allocated_irqresource(dev,
+ extended_irq->interrupts[i],
+ extended_irq->triggering,
+ extended_irq->polarity,
+ extended_irq->sharable);
+ }
+
+ /*
+ * The IRQ encoder puts a single interrupt in each
+ * descriptor, so if a _CRS descriptor has more than
+ * one interrupt, we won't be able to re-encode it.
+ */
+ if (pnp_can_write(dev) &&
+ extended_irq->interrupt_count > 1) {
+ dev_warn(&dev->dev, "multiple interrupts in "
+ "_CRS descriptor; configuration can't "
+ "be changed\n");
+ dev->capabilities &= ~PNP_WRITE;
+ }
}
break;
@@ -373,179 +467,147 @@ int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
}
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_dma *p)
{
int i;
- struct pnp_dma *dma;
+ unsigned char map = 0, flags;
if (p->channel_count == 0)
return;
- dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
- if (!dma)
- return;
for (i = 0; i < p->channel_count; i++)
- dma->map |= 1 << p->channels[i];
-
- dma->flags = dma_flags(p->type, p->bus_master, p->transfer);
+ map |= 1 << p->channels[i];
- pnp_register_dma_resource(dev, option, dma);
+ flags = dma_flags(p->type, p->bus_master, p->transfer);
+ pnp_register_dma_resource(dev, option_flags, map, flags);
}
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_irq *p)
{
int i;
- struct pnp_irq *irq;
+ pnp_irq_mask_t map;
+ unsigned char flags;
if (p->interrupt_count == 0)
return;
- irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
- if (!irq)
- return;
+ bitmap_zero(map.bits, PNP_IRQ_NR);
for (i = 0; i < p->interrupt_count; i++)
if (p->interrupts[i])
- __set_bit(p->interrupts[i], irq->map);
- irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
+ __set_bit(p->interrupts[i], map.bits);
- pnp_register_irq_resource(dev, option, irq);
+ flags = irq_flags(p->triggering, p->polarity, p->sharable);
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_extended_irq *p)
{
int i;
- struct pnp_irq *irq;
+ pnp_irq_mask_t map;
+ unsigned char flags;
if (p->interrupt_count == 0)
return;
- irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
- if (!irq)
- return;
- for (i = 0; i < p->interrupt_count; i++)
- if (p->interrupts[i])
- __set_bit(p->interrupts[i], irq->map);
- irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
+ bitmap_zero(map.bits, PNP_IRQ_NR);
+ for (i = 0; i < p->interrupt_count; i++) {
+ if (p->interrupts[i]) {
+ if (p->interrupts[i] < PNP_IRQ_NR)
+ __set_bit(p->interrupts[i], map.bits);
+ else
+ dev_err(&dev->dev, "ignoring IRQ %d option "
+ "(too large for %d entry bitmap)\n",
+ p->interrupts[i], PNP_IRQ_NR);
+ }
+ }
- pnp_register_irq_resource(dev, option, irq);
+ flags = irq_flags(p->triggering, p->polarity, p->sharable);
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_io *io)
{
- struct pnp_port *port;
+ unsigned char flags = 0;
if (io->address_length == 0)
return;
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = io->minimum;
- port->max = io->maximum;
- port->align = io->alignment;
- port->size = io->address_length;
- port->flags = ACPI_DECODE_16 == io->io_decode ?
- PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(dev, option, port);
+
+ if (io->io_decode == ACPI_DECODE_16)
+ flags = IORESOURCE_IO_16BIT_ADDR;
+ pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
+ io->alignment, io->address_length, flags);
}
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_fixed_io *io)
{
- struct pnp_port *port;
-
if (io->address_length == 0)
return;
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = port->max = io->address;
- port->size = io->address_length;
- port->align = 0;
- port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(dev, option, port);
+
+ pnp_register_port_resource(dev, option_flags, io->address, io->address,
+ 0, io->address_length, IORESOURCE_IO_FIXED);
}
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_memory24 *p)
{
- struct pnp_mem *mem;
+ unsigned char flags = 0;
if (p->address_length == 0)
return;
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = p->minimum;
- mem->max = p->maximum;
- mem->align = p->alignment;
- mem->size = p->address_length;
-
- mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
- IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(dev, option, mem);
+ if (p->write_protect == ACPI_READ_WRITE_MEMORY)
+ flags = IORESOURCE_MEM_WRITEABLE;
+ pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
+ p->alignment, p->address_length, flags);
}
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_memory32 *p)
{
- struct pnp_mem *mem;
+ unsigned char flags = 0;
if (p->address_length == 0)
return;
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = p->minimum;
- mem->max = p->maximum;
- mem->align = p->alignment;
- mem->size = p->address_length;
-
- mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
- IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(dev, option, mem);
+ if (p->write_protect == ACPI_READ_WRITE_MEMORY)
+ flags = IORESOURCE_MEM_WRITEABLE;
+ pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
+ p->alignment, p->address_length, flags);
}
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_fixed_memory32 *p)
{
- struct pnp_mem *mem;
+ unsigned char flags = 0;
if (p->address_length == 0)
return;
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = mem->max = p->address;
- mem->size = p->address_length;
- mem->align = 0;
-
- mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
- IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(dev, option, mem);
+ if (p->write_protect == ACPI_READ_WRITE_MEMORY)
+ flags = IORESOURCE_MEM_WRITEABLE;
+ pnp_register_mem_resource(dev, option_flags, p->address, p->address,
+ 0, p->address_length, flags);
}
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
acpi_status status;
- struct pnp_mem *mem;
- struct pnp_port *port;
+ unsigned char flags = 0;
status = acpi_resource_to_address64(r, p);
if (!ACPI_SUCCESS(status)) {
@@ -558,49 +620,37 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
return;
if (p->resource_type == ACPI_MEMORY_RANGE) {
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = mem->max = p->minimum;
- mem->size = p->address_length;
- mem->align = 0;
- mem->flags = (p->info.mem.write_protect ==
- ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE
- : 0;
- pnp_register_mem_resource(dev, option, mem);
- } else if (p->resource_type == ACPI_IO_RANGE) {
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = port->max = p->minimum;
- port->size = p->address_length;
- port->align = 0;
- port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(dev, option, port);
- }
+ if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
+ flags = IORESOURCE_MEM_WRITEABLE;
+ pnp_register_mem_resource(dev, option_flags, p->minimum,
+ p->minimum, 0, p->address_length,
+ flags);
+ } else if (p->resource_type == ACPI_IO_RANGE)
+ pnp_register_port_resource(dev, option_flags, p->minimum,
+ p->minimum, 0, p->address_length,
+ IORESOURCE_IO_FIXED);
}
struct acpipnp_parse_option_s {
- struct pnp_option *option;
- struct pnp_option *option_independent;
struct pnp_dev *dev;
+ unsigned int option_flags;
};
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
void *data)
{
- int priority = 0;
+ int priority;
struct acpipnp_parse_option_s *parse_data = data;
struct pnp_dev *dev = parse_data->dev;
- struct pnp_option *option = parse_data->option;
+ unsigned int option_flags = parse_data->option_flags;
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
- pnpacpi_parse_irq_option(dev, option, &res->data.irq);
+ pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnpacpi_parse_dma_option(dev, option, &res->data.dma);
+ pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -620,31 +670,19 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
priority = PNP_RES_PRIORITY_INVALID;
break;
}
- /* TBD: Consider performance/robustness bits */
- option = pnp_register_dependent_option(dev, priority);
- if (!option)
- return AE_ERROR;
- parse_data->option = option;
+ parse_data->option_flags = pnp_new_dependent_set(dev, priority);
break;
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
- /*only one EndDependentFn is allowed */
- if (!parse_data->option_independent) {
- dev_warn(&dev->dev, "more than one EndDependentFn "
- "in _PRS\n");
- return AE_ERROR;
- }
- parse_data->option = parse_data->option_independent;
- parse_data->option_independent = NULL;
- dev_dbg(&dev->dev, "end dependent options\n");
+ parse_data->option_flags = 0;
break;
case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_port_option(dev, option, &res->data.io);
+ pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_fixed_port_option(dev, option,
+ pnpacpi_parse_fixed_port_option(dev, option_flags,
&res->data.fixed_io);
break;
@@ -653,29 +691,31 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_mem24_option(dev, option, &res->data.memory24);
+ pnpacpi_parse_mem24_option(dev, option_flags,
+ &res->data.memory24);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_mem32_option(dev, option, &res->data.memory32);
+ pnpacpi_parse_mem32_option(dev, option_flags,
+ &res->data.memory32);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_fixed_mem32_option(dev, option,
+ pnpacpi_parse_fixed_mem32_option(dev, option_flags,
&res->data.fixed_memory32);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_address_option(dev, option, res);
+ pnpacpi_parse_address_option(dev, option_flags, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnpacpi_parse_ext_irq_option(dev, option,
+ pnpacpi_parse_ext_irq_option(dev, option_flags,
&res->data.extended_irq);
break;
@@ -699,12 +739,9 @@ int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
dev_dbg(&dev->dev, "parse resource options\n");
- parse_data.option = pnp_register_independent_option(dev);
- if (!parse_data.option)
- return -ENOMEM;
-
- parse_data.option_independent = parse_data.option;
parse_data.dev = dev;
+ parse_data.option_flags = 0;
+
status = acpi_walk_resources(handle, METHOD_NAME__PRS,
pnpacpi_option_resource, &parse_data);
@@ -806,6 +843,13 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev,
struct acpi_resource_irq *irq = &resource->data.irq;
int triggering, polarity, shareable;
+ if (!pnp_resource_enabled(p)) {
+ irq->interrupt_count = 0;
+ dev_dbg(&dev->dev, " encode irq (%s)\n",
+ p ? "disabled" : "missing");
+ return;
+ }
+
decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
irq->triggering = triggering;
irq->polarity = polarity;
@@ -828,6 +872,13 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
int triggering, polarity, shareable;
+ if (!pnp_resource_enabled(p)) {
+ extended_irq->interrupt_count = 0;
+ dev_dbg(&dev->dev, " encode extended irq (%s)\n",
+ p ? "disabled" : "missing");
+ return;
+ }
+
decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
extended_irq->producer_consumer = ACPI_CONSUMER;
extended_irq->triggering = triggering;
@@ -848,6 +899,13 @@ static void pnpacpi_encode_dma(struct pnp_dev *dev,
{
struct acpi_resource_dma *dma = &resource->data.dma;
+ if (!pnp_resource_enabled(p)) {
+ dma->channel_count = 0;
+ dev_dbg(&dev->dev, " encode dma (%s)\n",
+ p ? "disabled" : "missing");
+ return;
+ }
+
/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
case IORESOURCE_DMA_TYPEA:
@@ -889,17 +947,21 @@ static void pnpacpi_encode_io(struct pnp_dev *dev,
{
struct acpi_resource_io *io = &resource->data.io;
- /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
- io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
- ACPI_DECODE_16 : ACPI_DECODE_10;
- io->minimum = p->start;
- io->maximum = p->end;
- io->alignment = 0; /* Correct? */
- io->address_length = p->end - p->start + 1;
-
- dev_dbg(&dev->dev, " encode io %#llx-%#llx decode %#x\n",
- (unsigned long long) p->start, (unsigned long long) p->end,
- io->io_decode);
+ if (pnp_resource_enabled(p)) {
+ /* Note: pnp_assign_port copies pnp_port->flags into p->flags */
+ io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
+ ACPI_DECODE_16 : ACPI_DECODE_10;
+ io->minimum = p->start;
+ io->maximum = p->end;
+ io->alignment = 0; /* Correct? */
+ io->address_length = p->end - p->start + 1;
+ } else {
+ io->minimum = 0;
+ io->address_length = 0;
+ }
+
+ dev_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum,
+ io->minimum + io->address_length - 1, io->io_decode);
}
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
@@ -908,11 +970,16 @@ static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
{
struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;
- fixed_io->address = p->start;
- fixed_io->address_length = p->end - p->start + 1;
+ if (pnp_resource_enabled(p)) {
+ fixed_io->address = p->start;
+ fixed_io->address_length = p->end - p->start + 1;
+ } else {
+ fixed_io->address = 0;
+ fixed_io->address_length = 0;
+ }
- dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n",
- (unsigned long long) p->start, (unsigned long long) p->end);
+ dev_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address,
+ fixed_io->address + fixed_io->address_length - 1);
}
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
@@ -921,17 +988,22 @@ static void pnpacpi_encode_mem24(struct pnp_dev *dev,
{
struct acpi_resource_memory24 *memory24 = &resource->data.memory24;
- /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
- memory24->write_protect =
- (p->flags & IORESOURCE_MEM_WRITEABLE) ?
- ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- memory24->minimum = p->start;
- memory24->maximum = p->end;
- memory24->alignment = 0;
- memory24->address_length = p->end - p->start + 1;
-
- dev_dbg(&dev->dev, " encode mem24 %#llx-%#llx write_protect %#x\n",
- (unsigned long long) p->start, (unsigned long long) p->end,
+ if (pnp_resource_enabled(p)) {
+ /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */
+ memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
+ ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+ memory24->minimum = p->start;
+ memory24->maximum = p->end;
+ memory24->alignment = 0;
+ memory24->address_length = p->end - p->start + 1;
+ } else {
+ memory24->minimum = 0;
+ memory24->address_length = 0;
+ }
+
+ dev_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n",
+ memory24->minimum,
+ memory24->minimum + memory24->address_length - 1,
memory24->write_protect);
}
@@ -941,16 +1013,21 @@ static void pnpacpi_encode_mem32(struct pnp_dev *dev,
{
struct acpi_resource_memory32 *memory32 = &resource->data.memory32;
- memory32->write_protect =
- (p->flags & IORESOURCE_MEM_WRITEABLE) ?
- ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- memory32->minimum = p->start;
- memory32->maximum = p->end;
- memory32->alignment = 0;
- memory32->address_length = p->end - p->start + 1;
+ if (pnp_resource_enabled(p)) {
+ memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
+ ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+ memory32->minimum = p->start;
+ memory32->maximum = p->end;
+ memory32->alignment = 0;
+ memory32->address_length = p->end - p->start + 1;
+ } else {
+ memory32->minimum = 0;
+ memory32->alignment = 0;
+ }
- dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx write_protect %#x\n",
- (unsigned long long) p->start, (unsigned long long) p->end,
+ dev_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n",
+ memory32->minimum,
+ memory32->minimum + memory32->address_length - 1,
memory32->write_protect);
}
@@ -960,15 +1037,20 @@ static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
{
struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;
- fixed_memory32->write_protect =
- (p->flags & IORESOURCE_MEM_WRITEABLE) ?
- ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- fixed_memory32->address = p->start;
- fixed_memory32->address_length = p->end - p->start + 1;
+ if (pnp_resource_enabled(p)) {
+ fixed_memory32->write_protect =
+ p->flags & IORESOURCE_MEM_WRITEABLE ?
+ ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+ fixed_memory32->address = p->start;
+ fixed_memory32->address_length = p->end - p->start + 1;
+ } else {
+ fixed_memory32->address = 0;
+ fixed_memory32->address_length = 0;
+ }
- dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx "
- "write_protect %#x\n",
- (unsigned long long) p->start, (unsigned long long) p->end,
+ dev_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n",
+ fixed_memory32->address,
+ fixed_memory32->address + fixed_memory32->address_length - 1,
fixed_memory32->write_protect);
}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 5ff9a4c0447..ca567671379 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -216,137 +216,116 @@ len_err:
static __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_mem *mem;
-
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = ((p[5] << 8) | p[4]) << 8;
- mem->max = ((p[7] << 8) | p[6]) << 8;
- mem->align = (p[9] << 8) | p[8];
- mem->size = ((p[11] << 8) | p[10]) << 8;
- mem->flags = p[3];
- pnp_register_mem_resource(dev, option, mem);
+ resource_size_t min, max, align, len;
+ unsigned char flags;
+
+ min = ((p[5] << 8) | p[4]) << 8;
+ max = ((p[7] << 8) | p[6]) << 8;
+ align = (p[9] << 8) | p[8];
+ len = ((p[11] << 8) | p[10]) << 8;
+ flags = p[3];
+ pnp_register_mem_resource(dev, option_flags, min, max, align, len,
+ flags);
}
static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_mem *mem;
-
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
- mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
- mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
- mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
- mem->flags = p[3];
- pnp_register_mem_resource(dev, option, mem);
+ resource_size_t min, max, align, len;
+ unsigned char flags;
+
+ min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
+ max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
+ align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
+ len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
+ flags = p[3];
+ pnp_register_mem_resource(dev, option_flags, min, max, align, len,
+ flags);
}
static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_mem *mem;
-
- mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
- if (!mem)
- return;
- mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
- mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
- mem->align = 0;
- mem->flags = p[3];
- pnp_register_mem_resource(dev, option, mem);
+ resource_size_t base, len;
+ unsigned char flags;
+
+ base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
+ len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
+ flags = p[3];
+ pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
}
static __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_irq *irq;
unsigned long bits;
+ pnp_irq_mask_t map;
+ unsigned char flags = IORESOURCE_IRQ_HIGHEDGE;
- irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
- if (!irq)
- return;
bits = (p[2] << 8) | p[1];
- bitmap_copy(irq->map, &bits, 16);
+
+ bitmap_zero(map.bits, PNP_IRQ_NR);
+ bitmap_copy(map.bits, &bits, 16);
+
if (size > 2)
- irq->flags = p[3];
- else
- irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(dev, option, irq);
+ flags = p[3];
+
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
static __init void pnpbios_parse_dma_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_dma *dma;
-
- dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
- if (!dma)
- return;
- dma->map = p[1];
- dma->flags = p[2];
- pnp_register_dma_resource(dev, option, dma);
+ pnp_register_dma_resource(dev, option_flags, p[1], p[2]);
}
static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_port *port;
-
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = (p[3] << 8) | p[2];
- port->max = (p[5] << 8) | p[4];
- port->align = p[6];
- port->size = p[7];
- port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(dev, option, port);
+ resource_size_t min, max, align, len;
+ unsigned char flags;
+
+ min = (p[3] << 8) | p[2];
+ max = (p[5] << 8) | p[4];
+ align = p[6];
+ len = p[7];
+ flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0;
+ pnp_register_port_resource(dev, option_flags, min, max, align, len,
+ flags);
}
static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev,
unsigned char *p, int size,
- struct pnp_option *option)
+ unsigned int option_flags)
{
- struct pnp_port *port;
-
- port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
- if (!port)
- return;
- port->min = port->max = (p[2] << 8) | p[1];
- port->size = p[3];
- port->align = 0;
- port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(dev, option, port);
+ resource_size_t base, len;
+
+ base = (p[2] << 8) | p[1];
+ len = p[3];
+ pnp_register_port_resource(dev, option_flags, base, base, 0, len,
+ IORESOURCE_IO_FIXED);
}
static __init unsigned char *
pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
- struct pnp_dev *dev)
+ struct pnp_dev *dev)
{
unsigned int len, tag;
- int priority = 0;
- struct pnp_option *option, *option_independent;
+ int priority;
+ unsigned int option_flags;
if (!p)
return NULL;
dev_dbg(&dev->dev, "parse resource options\n");
-
- option_independent = option = pnp_register_independent_option(dev);
- if (!option)
- return NULL;
-
+ option_flags = 0;
while ((char *)p < (char *)end) {
/* determine the type of tag */
@@ -363,37 +342,38 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
- pnpbios_parse_mem_option(dev, p, len, option);
+ pnpbios_parse_mem_option(dev, p, len, option_flags);
break;
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
- pnpbios_parse_mem32_option(dev, p, len, option);
+ pnpbios_parse_mem32_option(dev, p, len, option_flags);
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
- pnpbios_parse_fixed_mem32_option(dev, p, len, option);
+ pnpbios_parse_fixed_mem32_option(dev, p, len,
+ option_flags);
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
- pnpbios_parse_irq_option(dev, p, len, option);
+ pnpbios_parse_irq_option(dev, p, len, option_flags);
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
- pnpbios_parse_dma_option(dev, p, len, option);
+ pnpbios_parse_dma_option(dev, p, len, option_flags);
break;
case SMALL_TAG_PORT:
if (len != 7)
goto len_err;
- pnpbios_parse_port_option(dev, p, len, option);
+ pnpbios_parse_port_option(dev, p, len, option_flags);
break;
case SMALL_TAG_VENDOR:
@@ -403,28 +383,23 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
case SMALL_TAG_FIXEDPORT:
if (len != 3)
goto len_err;
- pnpbios_parse_fixed_port_option(dev, p, len, option);
+ pnpbios_parse_fixed_port_option(dev, p, len,
+ option_flags);
break;
case SMALL_TAG_STARTDEP:
if (len > 1)
goto len_err;
- priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
+ priority = PNP_RES_PRIORITY_ACCEPTABLE;
if (len > 0)
- priority = 0x100 | p[1];
- option = pnp_register_dependent_option(dev, priority);
- if (!option)
- return NULL;
+ priority = p[1];
+ option_flags = pnp_new_dependent_set(dev, priority);
break;
case SMALL_TAG_ENDDEP:
if (len != 0)
goto len_err;
- if (option_independent == option)
- dev_warn(&dev->dev, "missing "
- "SMALL_TAG_STARTDEP tag\n");
- option = option_independent;
- dev_dbg(&dev->dev, "end dependent options\n");
+ option_flags = 0;
break;
case SMALL_TAG_END:
@@ -526,8 +501,16 @@ len_err:
static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
struct resource *res)
{
- unsigned long base = res->start;
- unsigned long len = res->end - res->start + 1;
+ unsigned long base;
+ unsigned long len;
+
+ if (pnp_resource_enabled(res)) {
+ base = res->start;
+ len = res->end - res->start + 1;
+ } else {
+ base = 0;
+ len = 0;
+ }
p[4] = (base >> 8) & 0xff;
p[5] = ((base >> 8) >> 8) & 0xff;
@@ -536,15 +519,22 @@ static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
p[10] = (len >> 8) & 0xff;
p[11] = ((len >> 8) >> 8) & 0xff;
- dev_dbg(&dev->dev, " encode mem %#llx-%#llx\n",
- (unsigned long long) res->start, (unsigned long long) res->end);
+ dev_dbg(&dev->dev, " encode mem %#lx-%#lx\n", base, base + len - 1);
}
static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
struct resource *res)
{
- unsigned long base = res->start;
- unsigned long len = res->end - res->start + 1;
+ unsigned long base;
+ unsigned long len;
+
+ if (pnp_resource_enabled(res)) {
+ base = res->start;
+ len = res->end - res->start + 1;
+ } else {
+ base = 0;
+ len = 0;
+ }
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
@@ -559,15 +549,22 @@ static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
p[18] = (len >> 16) & 0xff;
p[19] = (len >> 24) & 0xff;
- dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx\n",
- (unsigned long long) res->start, (unsigned long long) res->end);
+ dev_dbg(&dev->dev, " encode mem32 %#lx-%#lx\n", base, base + len - 1);
}
static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
struct resource *res)
{
- unsigned long base = res->start;
- unsigned long len = res->end - res->start + 1;
+ unsigned long base;
+ unsigned long len;
+
+ if (pnp_resource_enabled(res)) {
+ base = res->start;
+ len = res->end - res->start + 1;
+ } else {
+ base = 0;
+ len = 0;
+ }
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
@@ -578,40 +575,54 @@ static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
p[10] = (len >> 16) & 0xff;
p[11] = (len >> 24) & 0xff;
- dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx\n",
- (unsigned long long) res->start, (unsigned long long) res->end);
+ dev_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx\n", base,
+ base + len - 1);
}
static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
struct resource *res)
{
- unsigned long map = 0;
+ unsigned long map;
+
+ if (pnp_resource_enabled(res))
+ map = 1 << res->start;
+ else
+ map = 0;
- map = 1 << res->start;
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
- dev_dbg(&dev->dev, " encode irq %llu\n",
- (unsigned long long)res->start);
+ dev_dbg(&dev->dev, " encode irq mask %#lx\n", map);
}
static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
struct resource *res)
{
- unsigned long map = 0;
+ unsigned long map;
+
+ if (pnp_resource_enabled(res))
+ map = 1 << res->start;
+ else
+ map = 0;
- map = 1 << res->start;
p[1] = map & 0xff;
- dev_dbg(&dev->dev, " encode dma %llu\n",
- (unsigned long long)res->start);
+ dev_dbg(&dev->dev, " encode dma mask %#lx\n", map);
}
static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
struct resource *res)
{
- unsigned long base = res->start;
- unsigned long len = res->end - res->start + 1;
+ unsigned long base;
+ unsigned long len;
+
+ if (pnp_resource_enabled(res)) {
+ base = res->start;
+ len = res->end - res->start + 1;
+ } else {
+ base = 0;
+ len = 0;
+ }
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
@@ -619,8 +630,7 @@ static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
p[5] = (base >> 8) & 0xff;
p[7] = len & 0xff;
- dev_dbg(&dev->dev, " encode io %#llx-%#llx\n",
- (unsigned long long) res->start, (unsigned long long) res->end);
+ dev_dbg(&dev->dev, " encode io %#lx-%#lx\n", base, base + len - 1);
}
static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
@@ -629,12 +639,20 @@ static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
+ if (pnp_resource_enabled(res)) {
+ base = res->start;
+ len = res->end - res->start + 1;
+ } else {
+ base = 0;
+ len = 0;
+ }
+
p[1] = base & 0xff;
p[2] = (base >> 8) & 0xff;
p[3] = len & 0xff;
- dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n",
- (unsigned long long) res->start, (unsigned long long) res->end);
+ dev_dbg(&dev->dev, " encode fixed_io %#lx-%#lx\n", base,
+ base + len - 1);
}
static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 1ff3bb585ab..55f55ed72dc 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -5,6 +5,8 @@
* when building up the resource structure for the first time.
*
* Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* Heavily based on PCI quirks handling which is
*
@@ -20,203 +22,207 @@
#include <linux/kallsyms.h>
#include "base.h"
+static void quirk_awe32_add_ports(struct pnp_dev *dev,
+ struct pnp_option *option,
+ unsigned int offset)
+{
+ struct pnp_option *new_option;
+
+ new_option = kmalloc(sizeof(struct pnp_option), GFP_KERNEL);
+ if (!new_option) {
+ dev_err(&dev->dev, "couldn't add ioport region to option set "
+ "%d\n", pnp_option_set(option));
+ return;
+ }
+
+ *new_option = *option;
+ new_option->u.port.min += offset;
+ new_option->u.port.max += offset;
+ list_add(&new_option->list, &option->list);
+
+ dev_info(&dev->dev, "added ioport region %#llx-%#llx to set %d\n",
+ (unsigned long long) new_option->u.port.min,
+ (unsigned long long) new_option->u.port.max,
+ pnp_option_set(option));
+}
+
static void quirk_awe32_resources(struct pnp_dev *dev)
{
- struct pnp_port *port, *port2, *port3;
- struct pnp_option *res = dev->dependent;
+ struct pnp_option *option;
+ unsigned int set = ~0;
/*
- * Unfortunately the isapnp_add_port_resource is too tightly bound
- * into the PnP discovery sequence, and cannot be used. Link in the
- * two extra ports (at offset 0x400 and 0x800 from the one given) by
- * hand.
+ * Add two extra ioport regions (at offset 0x400 and 0x800 from the
+ * one given) to every dependent option set.
*/
- for (; res; res = res->next) {
- port2 = pnp_alloc(sizeof(struct pnp_port));
- if (!port2)
- return;
- port3 = pnp_alloc(sizeof(struct pnp_port));
- if (!port3) {
- kfree(port2);
- return;
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option) &&
+ pnp_option_set(option) != set) {
+ set = pnp_option_set(option);
+ quirk_awe32_add_ports(dev, option, 0x800);
+ quirk_awe32_add_ports(dev, option, 0x400);
}
- port = res->port;
- memcpy(port2, port, sizeof(struct pnp_port));
- memcpy(port3, port, sizeof(struct pnp_port));
- port->next = port2;
- port2->next = port3;
- port2->min += 0x400;
- port2->max += 0x400;
- port3->min += 0x800;
- port3->max += 0x800;
- dev_info(&dev->dev,
- "AWE32 quirk - added ioports 0x%lx and 0x%lx\n",
- (unsigned long)port2->min,
- (unsigned long)port3->min);
}
}
static void quirk_cmi8330_resources(struct pnp_dev *dev)
{
- struct pnp_option *res = dev->dependent;
- unsigned long tmp;
-
- for (; res; res = res->next) {
-
- struct pnp_irq *irq;
- struct pnp_dma *dma;
+ struct pnp_option *option;
+ struct pnp_irq *irq;
+ struct pnp_dma *dma;
- for (irq = res->irq; irq; irq = irq->next) { // Valid irqs are 5, 7, 10
- tmp = 0x04A0;
- bitmap_copy(irq->map, &tmp, 16); // 0000 0100 1010 0000
- }
+ list_for_each_entry(option, &dev->options, list) {
+ if (!pnp_option_is_dependent(option))
+ continue;
- for (dma = res->dma; dma; dma = dma->next) // Valid 8bit dma channels are 1,3
+ if (option->type == IORESOURCE_IRQ) {
+ irq = &option->u.irq;
+ bitmap_zero(irq->map.bits, PNP_IRQ_NR);
+ __set_bit(5, irq->map.bits);
+ __set_bit(7, irq->map.bits);
+ __set_bit(10, irq->map.bits);
+ dev_info(&dev->dev, "set possible IRQs in "
+ "option set %d to 5, 7, 10\n",
+ pnp_option_set(option));
+ } else if (option->type == IORESOURCE_DMA) {
+ dma = &option->u.dma;
if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
- IORESOURCE_DMA_8BIT)
- dma->map = 0x000A;
+ IORESOURCE_DMA_8BIT &&
+ dma->map != 0x0A) {
+ dev_info(&dev->dev, "changing possible "
+ "DMA channel mask in option set %d "
+ "from %#02x to 0x0A (1, 3)\n",
+ pnp_option_set(option), dma->map);
+ dma->map = 0x0A;
+ }
+ }
}
- dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 "
- "and DMA channels to 1, 3\n");
}
static void quirk_sb16audio_resources(struct pnp_dev *dev)
{
+ struct pnp_option *option;
+ unsigned int prev_option_flags = ~0, n = 0;
struct pnp_port *port;
- struct pnp_option *res = dev->dependent;
- int changed = 0;
/*
- * The default range on the mpu port for these devices is 0x388-0x388.
+ * The default range on the OPL port for these devices is 0x388-0x388.
* Here we increase that range so that two such cards can be
* auto-configured.
*/
+ list_for_each_entry(option, &dev->options, list) {
+ if (prev_option_flags != option->flags) {
+ prev_option_flags = option->flags;
+ n = 0;
+ }
- for (; res; res = res->next) {
- port = res->port;
- if (!port)
- continue;
- port = port->next;
- if (!port)
- continue;
- port = port->next;
- if (!port)
- continue;
- if (port->min != port->max)
- continue;
- port->max += 0x70;
- changed = 1;
+ if (pnp_option_is_dependent(option) &&
+ option->type == IORESOURCE_IO) {
+ n++;
+ port = &option->u.port;
+ if (n == 3 && port->min == port->max) {
+ port->max += 0x70;
+ dev_info(&dev->dev, "increased option port "
+ "range from %#llx-%#llx to "
+ "%#llx-%#llx\n",
+ (unsigned long long) port->min,
+ (unsigned long long) port->min,
+ (unsigned long long) port->min,
+ (unsigned long long) port->max);
+ }
+ }
}
- if (changed)
- dev_info(&dev->dev, "SB audio device quirk - increased port range\n");
}
-static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev)
+static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev,
+ unsigned int set)
{
- struct pnp_option *head = NULL;
- struct pnp_option *prev = NULL;
- struct pnp_option *res;
-
- /*
- * Build a functional IRQ-less variant of each MPU option.
- */
-
- for (res = dev->dependent; res; res = res->next) {
- struct pnp_option *curr;
- struct pnp_port *port;
- struct pnp_port *copy;
+ struct pnp_option *tail = NULL, *first_new_option = NULL;
+ struct pnp_option *option, *new_option;
+ unsigned int flags;
- port = res->port;
- if (!port || !res->irq)
- continue;
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option))
+ tail = option;
+ }
+ if (!tail) {
+ dev_err(&dev->dev, "no dependent option sets\n");
+ return NULL;
+ }
- copy = pnp_alloc(sizeof *copy);
- if (!copy)
- break;
+ flags = pnp_new_dependent_set(dev, PNP_RES_PRIORITY_FUNCTIONAL);
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option) &&
+ pnp_option_set(option) == set) {
+ new_option = kmalloc(sizeof(struct pnp_option),
+ GFP_KERNEL);
+ if (!new_option) {
+ dev_err(&dev->dev, "couldn't clone dependent "
+ "set %d\n", set);
+ return NULL;
+ }
- copy->min = port->min;
- copy->max = port->max;
- copy->align = port->align;
- copy->size = port->size;
- copy->flags = port->flags;
+ *new_option = *option;
+ new_option->flags = flags;
+ if (!first_new_option)
+ first_new_option = new_option;
- curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
- if (!curr) {
- kfree(copy);
- break;
+ list_add(&new_option->list, &tail->list);
+ tail = new_option;
}
- curr->port = copy;
-
- if (prev)
- prev->next = curr;
- else
- head = curr;
- prev = curr;
}
- if (head)
- dev_info(&dev->dev, "adding IRQ-less MPU options\n");
- return head;
+ return first_new_option;
}
-static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
+
+static void quirk_add_irq_optional_dependent_sets(struct pnp_dev *dev)
{
- struct pnp_option *res;
+ struct pnp_option *new_option;
+ unsigned int num_sets, i, set;
struct pnp_irq *irq;
- /*
- * Distribute the independent IRQ over the dependent options
- */
-
- res = dev->independent;
- if (!res)
- return;
-
- irq = res->irq;
- if (!irq || irq->next)
- return;
-
- res = dev->dependent;
- if (!res)
- return;
-
- while (1) {
- struct pnp_irq *copy;
-
- copy = pnp_alloc(sizeof *copy);
- if (!copy)
- break;
-
- memcpy(copy->map, irq->map, sizeof copy->map);
- copy->flags = irq->flags;
+ num_sets = dev->num_dependent_sets;
+ for (i = 0; i < num_sets; i++) {
+ new_option = pnp_clone_dependent_set(dev, i);
+ if (!new_option)
+ return;
- copy->next = res->irq; /* Yes, this is NULL */
- res->irq = copy;
+ set = pnp_option_set(new_option);
+ while (new_option && pnp_option_set(new_option) == set) {
+ if (new_option->type == IORESOURCE_IRQ) {
+ irq = &new_option->u.irq;
+ irq->flags |= IORESOURCE_IRQ_OPTIONAL;
+ }
+ dbg_pnp_show_option(dev, new_option);
+ new_option = list_entry(new_option->list.next,
+ struct pnp_option, list);
+ }
- if (!res->next)
- break;
- res = res->next;
+ dev_info(&dev->dev, "added dependent option set %d (same as "
+ "set %d except IRQ optional)\n", set, i);
}
- kfree(irq);
-
- res->next = quirk_isapnp_mpu_options(dev);
-
- res = dev->independent;
- res->irq = NULL;
}
-static void quirk_isapnp_mpu_resources(struct pnp_dev *dev)
+static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
{
- struct pnp_option *res;
+ struct pnp_option *option;
+ struct pnp_irq *irq = NULL;
+ unsigned int independent_irqs = 0;
+
+ list_for_each_entry(option, &dev->options, list) {
+ if (option->type == IORESOURCE_IRQ &&
+ !pnp_option_is_dependent(option)) {
+ independent_irqs++;
+ irq = &option->u.irq;
+ }
+ }
- res = dev->dependent;
- if (!res)
+ if (independent_irqs != 1)
return;
- while (res->next)
- res = res->next;
-
- res->next = quirk_isapnp_mpu_options(dev);
+ irq->flags |= IORESOURCE_IRQ_OPTIONAL;
+ dev_info(&dev->dev, "made independent IRQ optional\n");
}
#include <linux/pci.h>
@@ -248,8 +254,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
for (j = 0;
(res = pnp_get_resource(dev, IORESOURCE_MEM, j));
j++) {
- if (res->flags & IORESOURCE_UNSET ||
- (res->start == 0 && res->end == 0))
+ if (res->start == 0 && res->end == 0)
continue;
pnp_start = res->start;
@@ -312,10 +317,10 @@ static struct pnp_fixup pnp_fixups[] = {
{"CTL0043", quirk_sb16audio_resources},
{"CTL0044", quirk_sb16audio_resources},
{"CTL0045", quirk_sb16audio_resources},
- /* Add IRQ-less MPU options */
+ /* Add IRQ-optional MPU options */
{"ADS7151", quirk_ad1815_mpu_resources},
- {"ADS7181", quirk_isapnp_mpu_resources},
- {"AZT0002", quirk_isapnp_mpu_resources},
+ {"ADS7181", quirk_add_irq_optional_dependent_sets},
+ {"AZT0002", quirk_add_irq_optional_dependent_sets},
/* PnP resources that might overlap PCI BARs */
{"PNP0c01", quirk_system_pci_resources},
{"PNP0c02", quirk_system_pci_resources},
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 390b50096e3..4cfe3a1efdf 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -3,6 +3,8 @@
*
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/module.h>
@@ -28,201 +30,121 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some
* option registration
*/
-struct pnp_option *pnp_build_option(int priority)
+struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type,
+ unsigned int option_flags)
{
- struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
+ struct pnp_option *option;
+ option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
if (!option)
return NULL;
- option->priority = priority & 0xff;
- /* make sure the priority is valid */
- if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
- option->priority = PNP_RES_PRIORITY_INVALID;
-
- return option;
-}
-
-struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
-{
- struct pnp_option *option;
-
- option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
-
- /* this should never happen but if it does we'll try to continue */
- if (dev->independent)
- dev_err(&dev->dev, "independent resource already registered\n");
- dev->independent = option;
+ option->flags = option_flags;
+ option->type = type;
- dev_dbg(&dev->dev, "new independent option\n");
+ list_add_tail(&option->list, &dev->options);
return option;
}
-struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
- int priority)
+int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
+ pnp_irq_mask_t *map, unsigned char flags)
{
struct pnp_option *option;
+ struct pnp_irq *irq;
- option = pnp_build_option(priority);
-
- if (dev->dependent) {
- struct pnp_option *parent = dev->dependent;
- while (parent->next)
- parent = parent->next;
- parent->next = option;
- } else
- dev->dependent = option;
-
- dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority);
- return option;
-}
-
-int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_irq *data)
-{
- struct pnp_irq *ptr;
-#ifdef DEBUG
- char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */
-#endif
+ option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags);
+ if (!option)
+ return -ENOMEM;
- ptr = option->irq;
- while (ptr && ptr->next)
- ptr = ptr->next;
- if (ptr)
- ptr->next = data;
- else
- option->irq = data;
+ irq = &option->u.irq;
+ irq->map = *map;
+ irq->flags = flags;
#ifdef CONFIG_PCI
{
int i;
for (i = 0; i < 16; i++)
- if (test_bit(i, data->map))
+ if (test_bit(i, irq->map.bits))
pcibios_penalize_isa_irq(i, 0);
}
#endif
-#ifdef DEBUG
- bitmap_scnprintf(buf, sizeof(buf), data->map, PNP_IRQ_NR);
- dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf,
- data->flags);
-#endif
+ dbg_pnp_show_option(dev, option);
return 0;
}
-int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_dma *data)
+int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
+ unsigned char map, unsigned char flags)
{
- struct pnp_dma *ptr;
-
- ptr = option->dma;
- while (ptr && ptr->next)
- ptr = ptr->next;
- if (ptr)
- ptr->next = data;
- else
- option->dma = data;
-
- dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map,
- data->flags);
- return 0;
-}
+ struct pnp_option *option;
+ struct pnp_dma *dma;
-int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_port *data)
-{
- struct pnp_port *ptr;
-
- ptr = option->port;
- while (ptr && ptr->next)
- ptr = ptr->next;
- if (ptr)
- ptr->next = data;
- else
- option->port = data;
-
- dev_dbg(&dev->dev, " io "
- "min %#x max %#x align %d size %d flags %#x\n",
- data->min, data->max, data->align, data->size, data->flags);
- return 0;
-}
+ option = pnp_build_option(dev, IORESOURCE_DMA, option_flags);
+ if (!option)
+ return -ENOMEM;
-int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
- struct pnp_mem *data)
-{
- struct pnp_mem *ptr;
-
- ptr = option->mem;
- while (ptr && ptr->next)
- ptr = ptr->next;
- if (ptr)
- ptr->next = data;
- else
- option->mem = data;
-
- dev_dbg(&dev->dev, " mem "
- "min %#x max %#x align %d size %d flags %#x\n",
- data->min, data->max, data->align, data->size, data->flags);
+ dma = &option->u.dma;
+ dma->map = map;
+ dma->flags = flags;
+
+ dbg_pnp_show_option(dev, option);
return 0;
}
-static void pnp_free_port(struct pnp_port *port)
+int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
+ resource_size_t min, resource_size_t max,
+ resource_size_t align, resource_size_t size,
+ unsigned char flags)
{
- struct pnp_port *next;
+ struct pnp_option *option;
+ struct pnp_port *port;
- while (port) {
- next = port->next;
- kfree(port);
- port = next;
- }
-}
+ option = pnp_build_option(dev, IORESOURCE_IO, option_flags);
+ if (!option)
+ return -ENOMEM;
-static void pnp_free_irq(struct pnp_irq *irq)
-{
- struct pnp_irq *next;
+ port = &option->u.port;
+ port->min = min;
+ port->max = max;
+ port->align = align;
+ port->size = size;
+ port->flags = flags;
- while (irq) {
- next = irq->next;
- kfree(irq);
- irq = next;
- }
+ dbg_pnp_show_option(dev, option);
+ return 0;
}
-static void pnp_free_dma(struct pnp_dma *dma)
+int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
+ resource_size_t min, resource_size_t max,
+ resource_size_t align, resource_size_t size,
+ unsigned char flags)
{
- struct pnp_dma *next;
+ struct pnp_option *option;
+ struct pnp_mem *mem;
- while (dma) {
- next = dma->next;
- kfree(dma);
- dma = next;
- }
-}
+ option = pnp_build_option(dev, IORESOURCE_MEM, option_flags);
+ if (!option)
+ return -ENOMEM;
-static void pnp_free_mem(struct pnp_mem *mem)
-{
- struct pnp_mem *next;
+ mem = &option->u.mem;
+ mem->min = min;
+ mem->max = max;
+ mem->align = align;
+ mem->size = size;
+ mem->flags = flags;
- while (mem) {
- next = mem->next;
- kfree(mem);
- mem = next;
- }
+ dbg_pnp_show_option(dev, option);
+ return 0;
}
-void pnp_free_option(struct pnp_option *option)
+void pnp_free_options(struct pnp_dev *dev)
{
- struct pnp_option *next;
-
- while (option) {
- next = option->next;
- pnp_free_port(option->port);
- pnp_free_irq(option->irq);
- pnp_free_dma(option->dma);
- pnp_free_mem(option->mem);
+ struct pnp_option *option, *tmp;
+
+ list_for_each_entry_safe(option, tmp, &dev->options, list) {
+ list_del(&option->list);
kfree(option);
- option = next;
}
}
@@ -237,7 +159,7 @@ void pnp_free_option(struct pnp_option *option)
!((*(enda) < *(startb)) || (*(endb) < *(starta)))
#define cannot_compare(flags) \
-((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
+((flags) & IORESOURCE_DISABLED)
int pnp_check_port(struct pnp_dev *dev, struct resource *res)
{
@@ -364,6 +286,61 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#ifdef CONFIG_PCI
+static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
+ unsigned int irq)
+{
+ u32 class;
+ u8 progif;
+
+ if (pci->irq == irq) {
+ dev_dbg(&pnp->dev, "device %s using irq %d\n",
+ pci_name(pci), irq);
+ return 1;
+ }
+
+ /*
+ * See pci_setup_device() and ata_pci_sff_activate_host() for
+ * similar IDE legacy detection.
+ */
+ pci_read_config_dword(pci, PCI_CLASS_REVISION, &class);
+ class >>= 8; /* discard revision ID */
+ progif = class & 0xff;
+ class >>= 8;
+
+ if (class == PCI_CLASS_STORAGE_IDE) {
+ /*
+ * Unless both channels are native-PCI mode only,
+ * treat the compatibility IRQs as busy.
+ */
+ if ((progif & 0x5) != 0x5)
+ if (pci_get_legacy_ide_irq(pci, 0) == irq ||
+ pci_get_legacy_ide_irq(pci, 1) == irq) {
+ dev_dbg(&pnp->dev, "legacy IDE device %s "
+ "using irq %d\n", pci_name(pci), irq);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int pci_uses_irq(struct pnp_dev *pnp, unsigned int irq)
+{
+#ifdef CONFIG_PCI
+ struct pci_dev *pci = NULL;
+
+ for_each_pci_dev(pci) {
+ if (pci_dev_uses_irq(pnp, pci, irq)) {
+ pci_dev_put(pci);
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
{
int i;
@@ -395,18 +372,9 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
}
}
-#ifdef CONFIG_PCI
/* check if the resource is being used by a pci device */
- {
- struct pci_dev *pci = NULL;
- for_each_pci_dev(pci) {
- if (pci->irq == *irq) {
- pci_dev_put(pci);
- return 0;
- }
- }
- }
-#endif
+ if (pci_uses_irq(dev, *irq))
+ return 0;
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
@@ -499,81 +467,37 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
#endif
}
-struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev,
- unsigned int type, unsigned int num)
+int pnp_resource_type(struct resource *res)
{
- struct pnp_resource_table *res = dev->res;
-
- switch (type) {
- case IORESOURCE_IO:
- if (num >= PNP_MAX_PORT)
- return NULL;
- return &res->port[num];
- case IORESOURCE_MEM:
- if (num >= PNP_MAX_MEM)
- return NULL;
- return &res->mem[num];
- case IORESOURCE_IRQ:
- if (num >= PNP_MAX_IRQ)
- return NULL;
- return &res->irq[num];
- case IORESOURCE_DMA:
- if (num >= PNP_MAX_DMA)
- return NULL;
- return &res->dma[num];
- }
- return NULL;
+ return res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_IRQ | IORESOURCE_DMA);
}
struct resource *pnp_get_resource(struct pnp_dev *dev,
unsigned int type, unsigned int num)
{
struct pnp_resource *pnp_res;
+ struct resource *res;
- pnp_res = pnp_get_pnp_resource(dev, type, num);
- if (pnp_res)
- return &pnp_res->res;
-
+ list_for_each_entry(pnp_res, &dev->resources, list) {
+ res = &pnp_res->res;
+ if (pnp_resource_type(res) == type && num-- == 0)
+ return res;
+ }
return NULL;
}
EXPORT_SYMBOL(pnp_get_resource);
-static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev, int type)
+static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
{
struct pnp_resource *pnp_res;
- int i;
- switch (type) {
- case IORESOURCE_IO:
- for (i = 0; i < PNP_MAX_PORT; i++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, i);
- if (pnp_res && !pnp_resource_valid(&pnp_res->res))
- return pnp_res;
- }
- break;
- case IORESOURCE_MEM:
- for (i = 0; i < PNP_MAX_MEM; i++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, i);
- if (pnp_res && !pnp_resource_valid(&pnp_res->res))
- return pnp_res;
- }
- break;
- case IORESOURCE_IRQ:
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, i);
- if (pnp_res && !pnp_resource_valid(&pnp_res->res))
- return pnp_res;
- }
- break;
- case IORESOURCE_DMA:
- for (i = 0; i < PNP_MAX_DMA; i++) {
- pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, i);
- if (pnp_res && !pnp_resource_valid(&pnp_res->res))
- return pnp_res;
- }
- break;
- }
- return NULL;
+ pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL);
+ if (!pnp_res)
+ return NULL;
+
+ list_add_tail(&pnp_res->list, &dev->resources);
+ return pnp_res;
}
struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
@@ -581,15 +505,10 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
{
struct pnp_resource *pnp_res;
struct resource *res;
- static unsigned char warned;
- pnp_res = pnp_new_resource(dev, IORESOURCE_IRQ);
+ pnp_res = pnp_new_resource(dev);
if (!pnp_res) {
- if (!warned) {
- dev_err(&dev->dev, "can't add resource for IRQ %d\n",
- irq);
- warned = 1;
- }
+ dev_err(&dev->dev, "can't add resource for IRQ %d\n", irq);
return NULL;
}
@@ -607,15 +526,10 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
{
struct pnp_resource *pnp_res;
struct resource *res;
- static unsigned char warned;
- pnp_res = pnp_new_resource(dev, IORESOURCE_DMA);
+ pnp_res = pnp_new_resource(dev);
if (!pnp_res) {
- if (!warned) {
- dev_err(&dev->dev, "can't add resource for DMA %d\n",
- dma);
- warned = 1;
- }
+ dev_err(&dev->dev, "can't add resource for DMA %d\n", dma);
return NULL;
}
@@ -634,16 +548,12 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
{
struct pnp_resource *pnp_res;
struct resource *res;
- static unsigned char warned;
- pnp_res = pnp_new_resource(dev, IORESOURCE_IO);
+ pnp_res = pnp_new_resource(dev);
if (!pnp_res) {
- if (!warned) {
- dev_err(&dev->dev, "can't add resource for IO "
- "%#llx-%#llx\n",(unsigned long long) start,
- (unsigned long long) end);
- warned = 1;
- }
+ dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx\n",
+ (unsigned long long) start,
+ (unsigned long long) end);
return NULL;
}
@@ -663,16 +573,12 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
{
struct pnp_resource *pnp_res;
struct resource *res;
- static unsigned char warned;
- pnp_res = pnp_new_resource(dev, IORESOURCE_MEM);
+ pnp_res = pnp_new_resource(dev);
if (!pnp_res) {
- if (!warned) {
- dev_err(&dev->dev, "can't add resource for MEM "
- "%#llx-%#llx\n",(unsigned long long) start,
- (unsigned long long) end);
- warned = 1;
- }
+ dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx\n",
+ (unsigned long long) start,
+ (unsigned long long) end);
return NULL;
}
@@ -686,6 +592,52 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
return pnp_res;
}
+/*
+ * Determine whether the specified resource is a possible configuration
+ * for this device.
+ */
+int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
+ resource_size_t size)
+{
+ struct pnp_option *option;
+ struct pnp_port *port;
+ struct pnp_mem *mem;
+ struct pnp_irq *irq;
+ struct pnp_dma *dma;
+
+ list_for_each_entry(option, &dev->options, list) {
+ if (option->type != type)
+ continue;
+
+ switch (option->type) {
+ case IORESOURCE_IO:
+ port = &option->u.port;
+ if (port->min == start && port->size == size)
+ return 1;
+ break;
+ case IORESOURCE_MEM:
+ mem = &option->u.mem;
+ if (mem->min == start && mem->size == size)
+ return 1;
+ break;
+ case IORESOURCE_IRQ:
+ irq = &option->u.irq;
+ if (start < PNP_IRQ_NR &&
+ test_bit(start, irq->map.bits))
+ return 1;
+ break;
+ case IORESOURCE_DMA:
+ dma = &option->u.dma;
+ if (dma->map & (1 << start))
+ return 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(pnp_possible_config);
+
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
static int __init pnp_setup_reserve_irq(char *str)
{
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 95b076c18c0..bbf78ef4ba0 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -2,6 +2,8 @@
* support.c - standard functions for the use of pnp protocol drivers
*
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/module.h>
@@ -16,6 +18,10 @@
*/
int pnp_is_active(struct pnp_dev *dev)
{
+ /*
+ * I don't think this is very reliable because pnp_disable_dev()
+ * only clears out auto-assigned resources.
+ */
if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
!pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
@@ -52,39 +58,154 @@ void pnp_eisa_id_to_string(u32 id, char *str)
str[7] = '\0';
}
+char *pnp_resource_type_name(struct resource *res)
+{
+ switch (pnp_resource_type(res)) {
+ case IORESOURCE_IO:
+ return "io";
+ case IORESOURCE_MEM:
+ return "mem";
+ case IORESOURCE_IRQ:
+ return "irq";
+ case IORESOURCE_DMA:
+ return "dma";
+ }
+ return NULL;
+}
+
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
{
#ifdef DEBUG
+ char buf[128];
+ int len = 0;
+ struct pnp_resource *pnp_res;
struct resource *res;
- int i;
- dev_dbg(&dev->dev, "current resources: %s\n", desc);
-
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- res = pnp_get_resource(dev, IORESOURCE_IRQ, i);
- if (res && !(res->flags & IORESOURCE_UNSET))
- dev_dbg(&dev->dev, " irq %lld flags %#lx\n",
- (unsigned long long) res->start, res->flags);
+ if (list_empty(&dev->resources)) {
+ dev_dbg(&dev->dev, "%s: no current resources\n", desc);
+ return;
}
- for (i = 0; i < PNP_MAX_DMA; i++) {
- res = pnp_get_resource(dev, IORESOURCE_DMA, i);
- if (res && !(res->flags & IORESOURCE_UNSET))
- dev_dbg(&dev->dev, " dma %lld flags %#lx\n",
- (unsigned long long) res->start, res->flags);
+
+ dev_dbg(&dev->dev, "%s: current resources:\n", desc);
+ list_for_each_entry(pnp_res, &dev->resources, list) {
+ res = &pnp_res->res;
+
+ len += snprintf(buf + len, sizeof(buf) - len, " %-3s ",
+ pnp_resource_type_name(res));
+
+ if (res->flags & IORESOURCE_DISABLED) {
+ dev_dbg(&dev->dev, "%sdisabled\n", buf);
+ continue;
+ }
+
+ switch (pnp_resource_type(res)) {
+ case IORESOURCE_IO:
+ case IORESOURCE_MEM:
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%#llx-%#llx flags %#lx",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end,
+ res->flags);
+ break;
+ case IORESOURCE_IRQ:
+ case IORESOURCE_DMA:
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%lld flags %#lx",
+ (unsigned long long) res->start,
+ res->flags);
+ break;
+ }
+ dev_dbg(&dev->dev, "%s\n", buf);
}
- for (i = 0; i < PNP_MAX_PORT; i++) {
- res = pnp_get_resource(dev, IORESOURCE_IO, i);
- if (res && !(res->flags & IORESOURCE_UNSET))
- dev_dbg(&dev->dev, " io %#llx-%#llx flags %#lx\n",
- (unsigned long long) res->start,
- (unsigned long long) res->end, res->flags);
+#endif
+}
+
+char *pnp_option_priority_name(struct pnp_option *option)
+{
+ switch (pnp_option_priority(option)) {
+ case PNP_RES_PRIORITY_PREFERRED:
+ return "preferred";
+ case PNP_RES_PRIORITY_ACCEPTABLE:
+ return "acceptable";
+ case PNP_RES_PRIORITY_FUNCTIONAL:
+ return "functional";
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
- res = pnp_get_resource(dev, IORESOURCE_MEM, i);
- if (res && !(res->flags & IORESOURCE_UNSET))
- dev_dbg(&dev->dev, " mem %#llx-%#llx flags %#lx\n",
- (unsigned long long) res->start,
- (unsigned long long) res->end, res->flags);
+ return "invalid";
+}
+
+void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option)
+{
+#ifdef DEBUG
+ char buf[128];
+ int len = 0, i;
+ struct pnp_port *port;
+ struct pnp_mem *mem;
+ struct pnp_irq *irq;
+ struct pnp_dma *dma;
+
+ if (pnp_option_is_dependent(option))
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " dependent set %d (%s) ",
+ pnp_option_set(option),
+ pnp_option_priority_name(option));
+ else
+ len += snprintf(buf + len, sizeof(buf) - len, " independent ");
+
+ switch (option->type) {
+ case IORESOURCE_IO:
+ port = &option->u.port;
+ len += snprintf(buf + len, sizeof(buf) - len, "io min %#llx "
+ "max %#llx align %lld size %lld flags %#x",
+ (unsigned long long) port->min,
+ (unsigned long long) port->max,
+ (unsigned long long) port->align,
+ (unsigned long long) port->size, port->flags);
+ break;
+ case IORESOURCE_MEM:
+ mem = &option->u.mem;
+ len += snprintf(buf + len, sizeof(buf) - len, "mem min %#llx "
+ "max %#llx align %lld size %lld flags %#x",
+ (unsigned long long) mem->min,
+ (unsigned long long) mem->max,
+ (unsigned long long) mem->align,
+ (unsigned long long) mem->size, mem->flags);
+ break;
+ case IORESOURCE_IRQ:
+ irq = &option->u.irq;
+ len += snprintf(buf + len, sizeof(buf) - len, "irq");
+ if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " <none>");
+ else {
+ for (i = 0; i < PNP_IRQ_NR; i++)
+ if (test_bit(i, irq->map.bits))
+ len += snprintf(buf + len,
+ sizeof(buf) - len,
+ " %d", i);
+ }
+ len += snprintf(buf + len, sizeof(buf) - len, " flags %#x",
+ irq->flags);
+ if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " (optional)");
+ break;
+ case IORESOURCE_DMA:
+ dma = &option->u.dma;
+ len += snprintf(buf + len, sizeof(buf) - len, "dma");
+ if (!dma->map)
+ len += snprintf(buf + len, sizeof(buf) - len,
+ " <none>");
+ else {
+ for (i = 0; i < 8; i++)
+ if (dma->map & (1 << i))
+ len += snprintf(buf + len,
+ sizeof(buf) - len,
+ " %d", i);
+ }
+ len += snprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) "
+ "flags %#x", dma->map, dma->flags);
+ break;
}
+ dev_dbg(&dev->dev, "%s\n", buf);
#endif
}
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index cf4e07b01d4..764f3a31068 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -60,7 +60,7 @@ static void reserve_resources_of_dev(struct pnp_dev *dev)
int i;
for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
- if (res->flags & IORESOURCE_UNSET)
+ if (res->flags & IORESOURCE_DISABLED)
continue;
if (res->start == 0)
continue; /* disabled */
@@ -81,7 +81,7 @@ static void reserve_resources_of_dev(struct pnp_dev *dev)
}
for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
- if (res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
+ if (res->flags & IORESOURCE_DISABLED)
continue;
reserve_range(dev, res->start, res->end, 0);
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 97c68d021d2..638b68649e7 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -383,21 +383,14 @@ static int __devinit check_name(char *name)
return 0;
}
-static int __devinit check_resources(struct pnp_option *option)
+static int __devinit check_resources(struct pnp_dev *dev)
{
- struct pnp_option *tmp;
- if (!option)
- return 0;
+ resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+ int i;
- for (tmp = option; tmp; tmp = tmp->next) {
- struct pnp_port *port;
- for (port = tmp->port; port; port = port->next)
- if ((port->size == 8) &&
- ((port->min == 0x2f8) ||
- (port->min == 0x3f8) ||
- (port->min == 0x2e8) ||
- (port->min == 0x3e8)))
- return 1;
+ for (i = 0; i < ARRAY_SIZE(base); i++) {
+ if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
+ return 1;
}
return 0;
@@ -420,10 +413,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
(dev->card && check_name(dev->card->name))))
return -ENODEV;
- if (check_resources(dev->independent))
- return 0;
-
- if (check_resources(dev->dependent))
+ if (check_resources(dev))
return 0;
return -ENODEV;
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index 0fd5820d5c6..df52cb355f7 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -94,21 +94,31 @@ static const u8 ds2482_chan_rd[8] =
#define DS2482_REG_STS_1WB 0x01
-static int ds2482_attach_adapter(struct i2c_adapter *adapter);
-static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind);
-static int ds2482_detach_client(struct i2c_client *client);
+static int ds2482_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int ds2482_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info);
+static int ds2482_remove(struct i2c_client *client);
/**
* Driver data (common to all clients)
*/
+static const struct i2c_device_id ds2482_id[] = {
+ { "ds2482", 0 },
+ { }
+};
+
static struct i2c_driver ds2482_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ds2482",
},
- .attach_adapter = ds2482_attach_adapter,
- .detach_client = ds2482_detach_client,
+ .probe = ds2482_probe,
+ .remove = ds2482_remove,
+ .id_table = ds2482_id,
+ .detect = ds2482_detect,
+ .address_data = &addr_data,
};
/*
@@ -124,7 +134,7 @@ struct ds2482_w1_chan {
};
struct ds2482_data {
- struct i2c_client client;
+ struct i2c_client *client;
struct mutex access_lock;
/* 1-wire interface(s) */
@@ -147,7 +157,7 @@ struct ds2482_data {
static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
{
if (pdev->read_prt != read_ptr) {
- if (i2c_smbus_write_byte_data(&pdev->client,
+ if (i2c_smbus_write_byte_data(pdev->client,
DS2482_CMD_SET_READ_PTR,
read_ptr) < 0)
return -1;
@@ -167,7 +177,7 @@ static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
*/
static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
{
- if (i2c_smbus_write_byte(&pdev->client, cmd) < 0)
+ if (i2c_smbus_write_byte(pdev->client, cmd) < 0)
return -1;
pdev->read_prt = DS2482_PTR_CODE_STATUS;
@@ -187,7 +197,7 @@ static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
u8 cmd, u8 byte)
{
- if (i2c_smbus_write_byte_data(&pdev->client, cmd, byte) < 0)
+ if (i2c_smbus_write_byte_data(pdev->client, cmd, byte) < 0)
return -1;
/* all cmds leave in STATUS, except CONFIG */
@@ -216,7 +226,7 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
if (!ds2482_select_register(pdev, DS2482_PTR_CODE_STATUS)) {
do {
- temp = i2c_smbus_read_byte(&pdev->client);
+ temp = i2c_smbus_read_byte(pdev->client);
} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
(++retries < DS2482_WAIT_IDLE_TIMEOUT));
}
@@ -238,13 +248,13 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
*/
static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
{
- if (i2c_smbus_write_byte_data(&pdev->client, DS2482_CMD_CHANNEL_SELECT,
+ if (i2c_smbus_write_byte_data(pdev->client, DS2482_CMD_CHANNEL_SELECT,
ds2482_chan_wr[channel]) < 0)
return -1;
pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
pdev->channel = -1;
- if (i2c_smbus_read_byte(&pdev->client) == ds2482_chan_rd[channel]) {
+ if (i2c_smbus_read_byte(pdev->client) == ds2482_chan_rd[channel]) {
pdev->channel = channel;
return 0;
}
@@ -368,7 +378,7 @@ static u8 ds2482_w1_read_byte(void *data)
ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
/* Read the data byte */
- result = i2c_smbus_read_byte(&pdev->client);
+ result = i2c_smbus_read_byte(pdev->client);
mutex_unlock(&pdev->access_lock);
@@ -415,47 +425,38 @@ static u8 ds2482_w1_reset_bus(void *data)
}
-/**
- * Called to see if the device exists on an i2c bus.
- */
-static int ds2482_attach_adapter(struct i2c_adapter *adapter)
+static int ds2482_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
- return i2c_probe(adapter, &addr_data, ds2482_detect);
-}
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_BYTE))
+ return -ENODEV;
+ strlcpy(info->type, "ds2482", I2C_NAME_SIZE);
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
+ return 0;
+}
+
+static int ds2482_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds2482_data *data;
- struct i2c_client *new_client;
- int err = 0;
+ int err = -ENODEV;
int temp1;
int idx;
- if (!i2c_check_functionality(adapter,
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
- I2C_FUNC_SMBUS_BYTE))
- goto exit;
-
if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->driver = &ds2482_driver;
- new_client->adapter = adapter;
+ data->client = client;
+ i2c_set_clientdata(client, data);
/* Reset the device (sets the read_ptr to status) */
if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) {
- dev_dbg(&adapter->dev, "DS2482 reset failed at 0x%02x.\n",
- address);
+ dev_warn(&client->dev, "DS2482 reset failed.\n");
goto exit_free;
}
@@ -463,10 +464,10 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
ndelay(525);
/* Read the status byte - only reset bit and line should be set */
- temp1 = i2c_smbus_read_byte(new_client);
+ temp1 = i2c_smbus_read_byte(client);
if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
- dev_dbg(&adapter->dev, "DS2482 (0x%02x) reset status "
- "0x%02X - not a DS2482\n", address, temp1);
+ dev_warn(&client->dev, "DS2482 reset status "
+ "0x%02X - not a DS2482\n", temp1);
goto exit_free;
}
@@ -478,16 +479,8 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
/* Set all config items to 0 (off) */
ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0);
- /* We can fill in the remaining client fields */
- snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00",
- data->w1_count);
-
mutex_init(&data->access_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Register 1-wire interface(s) */
for (idx = 0; idx < data->w1_count; idx++) {
data->w1_ch[idx].pdev = data;
@@ -511,8 +504,6 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_w1_remove:
- i2c_detach_client(new_client);
-
for (idx = 0; idx < data->w1_count; idx++) {
if (data->w1_ch[idx].pdev != NULL)
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
@@ -523,10 +514,10 @@ exit:
return err;
}
-static int ds2482_detach_client(struct i2c_client *client)
+static int ds2482_remove(struct i2c_client *client)
{
struct ds2482_data *data = i2c_get_clientdata(client);
- int err, idx;
+ int idx;
/* Unregister the 1-wire bridge(s) */
for (idx = 0; idx < data->w1_count; idx++) {
@@ -534,13 +525,6 @@ static int ds2482_detach_client(struct i2c_client *client)
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
}
- /* Detach the i2c device */
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Deregistration failed, client not detached.\n");
- return err;
- }
-
/* Free the memory */
kfree(data);
return 0;
diff --git a/firmware/.gitignore b/firmware/.gitignore
new file mode 100644
index 00000000000..d9c69017bc9
--- /dev/null
+++ b/firmware/.gitignore
@@ -0,0 +1,6 @@
+*.gen.S
+*.fw
+*.bin
+*.csp
+*.dsp
+ihex2fw
diff --git a/firmware/Makefile b/firmware/Makefile
index e4f2fb3d191..9fe86041f86 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -56,7 +56,7 @@ fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28X) += keyspan/usa28x.fw
fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49W) += keyspan/usa49w.fw
fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49WLC) += keyspan/usa49wlc.fw
else
-fw-shipped- := keyspan/mpr.fw keyspan/usa18x.fw keyspan/usa19.fw \
+fw-shipped- += keyspan/mpr.fw keyspan/usa18x.fw keyspan/usa19.fw \
keyspan/usa19qi.fw keyspan/usa19qw.fw keyspan/usa19w.fw \
keyspan/usa28.fw keyspan/usa28xa.fw keyspan/usa28xb.fw \
keyspan/usa28x.fw keyspan/usa49w.fw keyspan/usa49wlc.fw
diff --git a/fs/Kconfig b/fs/Kconfig
index 313b2e06ded..84ab76a206a 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1544,10 +1544,6 @@ config UFS_FS
The recently released UFS2 variant (used in FreeBSD 5.x) is
READ-ONLY supported.
- If you only intend to mount files from some other Unix over the
- network using NFS, you don't need the UFS file system support (but
- you need NFS file system support obviously).
-
Note that this option is generally not needed for floppies, since a
good portable way to transport files and directories between unixes
(and even other operating systems) is given by the tar program ("man
@@ -1587,6 +1583,7 @@ menuconfig NETWORK_FILESYSTEMS
Say Y here to get to see options for network filesystems and
filesystem-related networking code, such as NFS daemon and
RPCSEC security modules.
+
This option alone does not add any kernel code.
If you say N, all options in this submenu will be skipped and
@@ -1595,76 +1592,92 @@ menuconfig NETWORK_FILESYSTEMS
if NETWORK_FILESYSTEMS
config NFS_FS
- tristate "NFS file system support"
+ tristate "NFS client support"
depends on INET
select LOCKD
select SUNRPC
select NFS_ACL_SUPPORT if NFS_V3_ACL
help
- If you are connected to some other (usually local) Unix computer
- (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
- on that computer (the NFS server) using the Network File Sharing
- protocol, say Y. "Mounting files" means that the client can access
- the files with usual UNIX commands as if they were sitting on the
- client's hard disk. For this to work, the server must run the
- programs nfsd and mountd (but does not need to have NFS file system
- support enabled in its kernel). NFS is explained in the Network
- Administrator's Guide, available from
- <http://www.tldp.org/docs.html#guide>, on its man page: "man
- nfs", and in the NFS-HOWTO.
-
- A superior but less widely used alternative to NFS is provided by
- the Coda file system; see "Coda file system support" below.
+ Choose Y here if you want to access files residing on other
+ computers using Sun's Network File System protocol. To compile
+ this file system support as a module, choose M here: the module
+ will be called nfs.
- If you say Y here, you should have said Y to TCP/IP networking also.
- This option would enlarge your kernel by about 27 KB.
+ To mount file systems exported by NFS servers, you also need to
+ install the user space mount.nfs command which can be found in
+ the Linux nfs-utils package, available from http://linux-nfs.org/.
+ Information about using the mount command is available in the
+ mount(8) man page. More detail about the Linux NFS client
+ implementation is available via the nfs(5) man page.
- To compile this file system support as a module, choose M here: the
- module will be called nfs.
+ Below you can choose which versions of the NFS protocol are
+ available in the kernel to mount NFS servers. Support for NFS
+ version 2 (RFC 1094) is always available when NFS_FS is selected.
- If you are configuring a diskless machine which will mount its root
- file system over NFS at boot time, say Y here and to "Kernel
- level IP autoconfiguration" above and to "Root file system on NFS"
- below. You cannot compile this driver as a module in this case.
- There are two packages designed for booting diskless machines over
- the net: netboot, available from
- <http://ftp1.sourceforge.net/netboot/>, and Etherboot,
- available from <http://ftp1.sourceforge.net/etherboot/>.
+ To configure a system which mounts its root file system via NFS
+ at boot time, say Y here, select "Kernel level IP
+ autoconfiguration" in the NETWORK menu, and select "Root file
+ system on NFS" below. You cannot compile this file system as a
+ module in this case.
- If you don't know what all this is about, say N.
+ If unsure, say N.
config NFS_V3
- bool "Provide NFSv3 client support"
+ bool "NFS client support for NFS version 3"
depends on NFS_FS
help
- Say Y here if you want your NFS client to be able to speak version
- 3 of the NFS protocol.
+ This option enables support for version 3 of the NFS protocol
+ (RFC 1813) in the kernel's NFS client.
If unsure, say Y.
config NFS_V3_ACL
- bool "Provide client support for the NFSv3 ACL protocol extension"
+ bool "NFS client support for the NFSv3 ACL protocol extension"
depends on NFS_V3
help
- Implement the NFSv3 ACL protocol extension for manipulating POSIX
- Access Control Lists. The server should also be compiled with
- the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option.
+ Some NFS servers support an auxiliary NFSv3 ACL protocol that
+ Sun added to Solaris but never became an official part of the
+ NFS version 3 protocol. This protocol extension allows
+ applications on NFS clients to manipulate POSIX Access Control
+ Lists on files residing on NFS servers. NFS servers enforce
+ ACLs on local files whether this protocol is available or not.
+
+ Choose Y here if your NFS server supports the Solaris NFSv3 ACL
+ protocol extension and you want your NFS client to allow
+ applications to access and modify ACLs on files on the server.
+
+ Most NFS servers don't support the Solaris NFSv3 ACL protocol
+ extension. You can choose N here or specify the "noacl" mount
+ option to prevent your NFS client from trying to use the NFSv3
+ ACL protocol.
If unsure, say N.
config NFS_V4
- bool "Provide NFSv4 client support (EXPERIMENTAL)"
+ bool "NFS client support for NFS version 4 (EXPERIMENTAL)"
depends on NFS_FS && EXPERIMENTAL
select RPCSEC_GSS_KRB5
help
- Say Y here if you want your NFS client to be able to speak the newer
- version 4 of the NFS protocol.
+ This option enables support for version 4 of the NFS protocol
+ (RFC 3530) in the kernel's NFS client.
- Note: Requires auxiliary userspace daemons which may be found on
- http://www.citi.umich.edu/projects/nfsv4/
+ To mount NFS servers using NFSv4, you also need to install user
+ space programs which can be found in the Linux nfs-utils package,
+ available from http://linux-nfs.org/.
If unsure, say N.
+config ROOT_NFS
+ bool "Root file system on NFS"
+ depends on NFS_FS=y && IP_PNP
+ help
+ If you want your system to mount its root file system via NFS,
+ choose Y here. This is common practice for managing systems
+ without local permanent storage. For details, read
+ <file:Documentation/filesystems/nfsroot.txt>.
+
+ Most people say N here.
+
config NFSD
tristate "NFS server support"
depends on INET
@@ -1746,20 +1759,6 @@ config NFSD_V4
If unsure, say N.
-config ROOT_NFS
- bool "Root file system on NFS"
- depends on NFS_FS=y && IP_PNP
- help
- If you want your Linux box to mount its whole root file system (the
- one containing the directory /) from some other computer over the
- net via NFS (presumably because your box doesn't have a hard disk),
- say Y. Read <file:Documentation/filesystems/nfsroot.txt> for
- details. It is likely that in this case, you also want to say Y to
- "Kernel level IP autoconfiguration" so that your box can discover
- its network address at boot time.
-
- Most people say N here.
-
config LOCKD
tristate
@@ -1800,27 +1799,6 @@ config SUNRPC_XPRT_RDMA
If unsure, say N.
-config SUNRPC_BIND34
- bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
- depends on SUNRPC && EXPERIMENTAL
- default n
- help
- RPC requests over IPv6 networks require support for larger
- addresses when performing an RPC bind. Sun added support for
- IPv6 addressing by creating two new versions of the rpcbind
- protocol (RFC 1833).
-
- This option enables support in the kernel RPC client for
- querying rpcbind servers via versions 3 and 4 of the rpcbind
- protocol. The kernel automatically falls back to version 2
- if a remote rpcbind service does not support versions 3 or 4.
- By themselves, these new versions do not provide support for
- RPC over IPv6, but the new protocol versions are necessary to
- support it.
-
- If unsure, say N to get traditional behavior (version 2 rpcbind
- requests only).
-
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 97dba0d9234..c54eaab71a1 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -69,9 +69,11 @@
#include <linux/capi.h>
#include <linux/gigaset_dev.h>
+#ifdef CONFIG_BLOCK
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>
+#endif
#include <asm/uaccess.h>
#include <linux/ethtool.h>
@@ -2024,6 +2026,7 @@ COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
COMPATIBLE_IOCTL(PIO_FONTRESET)
COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
+#ifdef CONFIG_BLOCK
/* Big S */
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
@@ -2033,6 +2036,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
+#endif
/* Big T */
COMPATIBLE_IOCTL(TUNSETNOCSUM)
COMPATIBLE_IOCTL(TUNSETDEBUG)
@@ -2103,6 +2107,7 @@ COMPATIBLE_IOCTL(SIOCGIFVLAN)
COMPATIBLE_IOCTL(SIOCSIFVLAN)
COMPATIBLE_IOCTL(SIOCBRADDBR)
COMPATIBLE_IOCTL(SIOCBRDELBR)
+#ifdef CONFIG_BLOCK
/* SG stuff */
COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
@@ -2127,6 +2132,7 @@ COMPATIBLE_IOCTL(SG_SCSI_RESET)
COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
+#endif
/* PPP stuff */
COMPATIBLE_IOCTL(PPPIOCGFLAGS)
COMPATIBLE_IOCTL(PPPIOCSFLAGS)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 5df517b81f3..1f6dc518505 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -224,7 +224,9 @@ void nlm_release_call(struct nlm_rqst *call)
static void nlmclnt_rpc_release(void *data)
{
+ lock_kernel();
nlm_release_call(data);
+ unlock_kernel();
}
static int nlm_wait_on_grace(wait_queue_head_t *queue)
@@ -430,7 +432,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
* Report the conflicting lock back to the application.
*/
fl->fl_start = req->a_res.lock.fl.fl_start;
- fl->fl_end = req->a_res.lock.fl.fl_start;
+ fl->fl_end = req->a_res.lock.fl.fl_end;
fl->fl_type = req->a_res.lock.fl.fl_type;
fl->fl_pid = 0;
break;
@@ -710,7 +712,9 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
die:
return;
retry_rebind:
+ lock_kernel();
nlm_rebind_host(req->a_host);
+ unlock_kernel();
retry_unlock:
rpc_restart_call(task);
}
@@ -788,7 +792,9 @@ retry_cancel:
/* Don't ever retry more than 3 times */
if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
goto die;
+ lock_kernel();
nlm_rebind_host(req->a_host);
+ unlock_kernel();
rpc_restart_call(task);
rpc_delay(task, 30 * HZ);
}
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 385437e3387..2e27176ff42 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -248,7 +248,9 @@ static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
static void nlm4svc_callback_release(void *data)
{
+ lock_kernel();
nlm_release_call(data);
+ unlock_kernel();
}
static const struct rpc_call_ops nlm4svc_callback_ops = {
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 81aca859bfd..56a08ab9a4c 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -795,6 +795,7 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
dprintk("lockd: GRANT_MSG RPC callback\n");
+ lock_kernel();
/* if the block is not on a list at this point then it has
* been invalidated. Don't try to requeue it.
*
@@ -804,7 +805,7 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
* for nlm_blocked?
*/
if (list_empty(&block->b_list))
- return;
+ goto out;
/* Technically, we should down the file semaphore here. Since we
* move the block towards the head of the queue only, no harm
@@ -818,13 +819,17 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
}
nlmsvc_insert_block(block, timeout);
svc_wake_up(block->b_daemon);
+out:
+ unlock_kernel();
}
static void nlmsvc_grant_release(void *data)
{
struct nlm_rqst *call = data;
+ lock_kernel();
nlmsvc_release_block(call->a_block);
+ unlock_kernel();
}
static const struct rpc_call_ops nlmsvc_grant_ops = {
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 88379cc6e0b..ce6952b50a7 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -278,7 +278,9 @@ static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
static void nlmsvc_callback_release(void *data)
{
+ lock_kernel();
nlm_release_call(data);
+ unlock_kernel();
}
static const struct rpc_call_ops nlmsvc_callback_ops = {
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index c1e7c830062..f447f4b4476 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -27,7 +27,7 @@
struct nfs_callback_data {
unsigned int users;
- struct svc_serv *serv;
+ struct svc_rqst *rqst;
struct task_struct *task;
};
@@ -91,21 +91,17 @@ nfs_callback_svc(void *vrqstp)
svc_process(rqstp);
}
unlock_kernel();
- nfs_callback_info.task = NULL;
- svc_exit_thread(rqstp);
return 0;
}
/*
- * Bring up the server process if it is not already up.
+ * Bring up the callback thread if it is not already up.
*/
int nfs_callback_up(void)
{
struct svc_serv *serv = NULL;
- struct svc_rqst *rqstp;
int ret = 0;
- lock_kernel();
mutex_lock(&nfs_callback_mutex);
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
goto out;
@@ -121,22 +117,23 @@ int nfs_callback_up(void)
nfs_callback_tcpport = ret;
dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
- rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
- if (IS_ERR(rqstp)) {
- ret = PTR_ERR(rqstp);
+ nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
+ if (IS_ERR(nfs_callback_info.rqst)) {
+ ret = PTR_ERR(nfs_callback_info.rqst);
+ nfs_callback_info.rqst = NULL;
goto out_err;
}
svc_sock_update_bufs(serv);
- nfs_callback_info.serv = serv;
- nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp,
+ nfs_callback_info.task = kthread_run(nfs_callback_svc,
+ nfs_callback_info.rqst,
"nfsv4-svc");
if (IS_ERR(nfs_callback_info.task)) {
ret = PTR_ERR(nfs_callback_info.task);
- nfs_callback_info.serv = NULL;
+ svc_exit_thread(nfs_callback_info.rqst);
+ nfs_callback_info.rqst = NULL;
nfs_callback_info.task = NULL;
- svc_exit_thread(rqstp);
goto out_err;
}
out:
@@ -149,7 +146,6 @@ out:
if (serv)
svc_destroy(serv);
mutex_unlock(&nfs_callback_mutex);
- unlock_kernel();
return ret;
out_err:
dprintk("Couldn't create callback socket or server thread; err = %d\n",
@@ -159,17 +155,19 @@ out_err:
}
/*
- * Kill the server process if it is not already down.
+ * Kill the callback thread if it's no longer being used.
*/
void nfs_callback_down(void)
{
- lock_kernel();
mutex_lock(&nfs_callback_mutex);
nfs_callback_info.users--;
- if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL)
+ if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) {
kthread_stop(nfs_callback_info.task);
+ svc_exit_thread(nfs_callback_info.rqst);
+ nfs_callback_info.rqst = NULL;
+ nfs_callback_info.task = NULL;
+ }
mutex_unlock(&nfs_callback_mutex);
- unlock_kernel();
}
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index f2a092ca69b..5ee23e7058b 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -431,14 +431,14 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
{
to->to_initval = timeo * HZ / 10;
to->to_retries = retrans;
- if (!to->to_retries)
- to->to_retries = 2;
switch (proto) {
case XPRT_TRANSPORT_TCP:
case XPRT_TRANSPORT_RDMA:
+ if (to->to_retries == 0)
+ to->to_retries = NFS_DEF_TCP_RETRANS;
if (to->to_initval == 0)
- to->to_initval = 60 * HZ;
+ to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
to->to_initval = NFS_MAX_TCP_TIMEOUT;
to->to_increment = to->to_initval;
@@ -450,14 +450,17 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_exponential = 0;
break;
case XPRT_TRANSPORT_UDP:
- default:
+ if (to->to_retries == 0)
+ to->to_retries = NFS_DEF_UDP_RETRANS;
if (!to->to_initval)
- to->to_initval = 11 * HZ / 10;
+ to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
to->to_initval = NFS_MAX_UDP_TIMEOUT;
to->to_maxval = NFS_MAX_UDP_TIMEOUT;
to->to_exponential = 1;
break;
+ default:
+ BUG();
}
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 982a2064fe4..28a238dab23 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -133,13 +133,14 @@ nfs_opendir(struct inode *inode, struct file *filp)
{
int res;
- dfprintk(VFS, "NFS: opendir(%s/%ld)\n",
- inode->i_sb->s_id, inode->i_ino);
+ dfprintk(FILE, "NFS: open dir(%s/%s)\n",
+ filp->f_path.dentry->d_parent->d_name.name,
+ filp->f_path.dentry->d_name.name);
+
+ nfs_inc_stats(inode, NFSIOS_VFSOPEN);
- lock_kernel();
/* Call generic open code in order to cache credentials */
res = nfs_open(inode, filp);
- unlock_kernel();
return res;
}
@@ -528,13 +529,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct nfs_fattr fattr;
long res;
- dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n",
+ dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(long long)filp->f_pos);
nfs_inc_stats(inode, NFSIOS_VFSGETDENTS);
- lock_kernel();
-
/*
* filp->f_pos points to the dirent entry number.
* *desc->dir_cookie has the cookie for the next entry. We have
@@ -592,10 +591,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
out:
nfs_unblock_sillyrename(dentry);
- unlock_kernel();
if (res > 0)
res = 0;
- dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n",
+ dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
res);
return res;
@@ -603,7 +601,15 @@ out:
static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
{
- mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
+ struct dentry *dentry = filp->f_path.dentry;
+ struct inode *inode = dentry->d_inode;
+
+ dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name,
+ offset, origin);
+
+ mutex_lock(&inode->i_mutex);
switch (origin) {
case 1:
offset += filp->f_pos;
@@ -619,7 +625,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
nfs_file_open_context(filp)->dir_cookie = 0;
}
out:
- mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
+ mutex_unlock(&inode->i_mutex);
return offset;
}
@@ -629,10 +635,11 @@ out:
*/
static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
{
- dfprintk(VFS, "NFS: fsync_dir(%s/%s) datasync %d\n",
+ dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
datasync);
+ nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC);
return 0;
}
@@ -767,7 +774,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
struct nfs_fattr fattr;
parent = dget_parent(dentry);
- lock_kernel();
dir = parent->d_inode;
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = dentry->d_inode;
@@ -805,7 +811,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
- unlock_kernel();
dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",
__func__, dentry->d_parent->d_name.name,
@@ -824,7 +829,6 @@ out_zap_parent:
shrink_dcache_parent(dentry);
}
d_drop(dentry);
- unlock_kernel();
dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
__func__, dentry->d_parent->d_name.name,
@@ -858,6 +862,14 @@ static int nfs_dentry_delete(struct dentry *dentry)
}
+static void nfs_drop_nlink(struct inode *inode)
+{
+ spin_lock(&inode->i_lock);
+ if (inode->i_nlink > 0)
+ drop_nlink(inode);
+ spin_unlock(&inode->i_lock);
+}
+
/*
* Called when the dentry loses inode.
* We use it to clean up silly-renamed files.
@@ -869,10 +881,8 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
- lock_kernel();
drop_nlink(inode);
nfs_complete_unlink(dentry, inode);
- unlock_kernel();
}
iput(inode);
}
@@ -903,8 +913,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(-ENOMEM);
dentry->d_op = NFS_PROTO(dir)->dentry_ops;
- lock_kernel();
-
/*
* If we're doing an exclusive create, optimize away the lookup
* but don't hash the dentry.
@@ -912,7 +920,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
if (nfs_is_exclusive_create(dir, nd)) {
d_instantiate(dentry, NULL);
res = NULL;
- goto out_unlock;
+ goto out;
}
parent = dentry->d_parent;
@@ -940,8 +948,6 @@ no_entry:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_unblock_sillyrename:
nfs_unblock_sillyrename(parent);
-out_unlock:
- unlock_kernel();
out:
return res;
}
@@ -999,9 +1005,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
}
/* Open the file on the server */
- lock_kernel();
res = nfs4_atomic_open(dir, dentry, nd);
- unlock_kernel();
if (IS_ERR(res)) {
error = PTR_ERR(res);
switch (error) {
@@ -1063,9 +1067,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
* operations that change the directory. We therefore save the
* change attribute *before* we do the RPC call.
*/
- lock_kernel();
ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
- unlock_kernel();
out:
dput(parent);
if (!ret)
@@ -1218,14 +1220,11 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
if ((nd->flags & LOOKUP_CREATE) != 0)
open_flags = nd->intent.open.flags;
- lock_kernel();
error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
if (error != 0)
goto out_err;
- unlock_kernel();
return 0;
out_err:
- unlock_kernel();
d_drop(dentry);
return error;
}
@@ -1248,14 +1247,11 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- lock_kernel();
status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
if (status != 0)
goto out_err;
- unlock_kernel();
return 0;
out_err:
- unlock_kernel();
d_drop(dentry);
return status;
}
@@ -1274,15 +1270,12 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
- lock_kernel();
error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
if (error != 0)
goto out_err;
- unlock_kernel();
return 0;
out_err:
d_drop(dentry);
- unlock_kernel();
return error;
}
@@ -1299,14 +1292,12 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
- lock_kernel();
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Ensure the VFS deletes this inode */
if (error == 0 && dentry->d_inode != NULL)
clear_nlink(dentry->d_inode);
else if (error == -ENOENT)
nfs_dentry_handle_enoent(dentry);
- unlock_kernel();
return error;
}
@@ -1408,7 +1399,7 @@ static int nfs_safe_remove(struct dentry *dentry)
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
/* The VFS may want to delete this inode */
if (error == 0)
- drop_nlink(inode);
+ nfs_drop_nlink(inode);
nfs_mark_for_revalidate(inode);
} else
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
@@ -1431,7 +1422,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name);
- lock_kernel();
spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
if (atomic_read(&dentry->d_count) > 1) {
@@ -1440,7 +1430,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
/* Start asynchronous writeout of the inode */
write_inode_now(dentry->d_inode, 0);
error = nfs_sillyrename(dir, dentry);
- unlock_kernel();
return error;
}
if (!d_unhashed(dentry)) {
@@ -1454,7 +1443,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
} else if (need_rehash)
d_rehash(dentry);
- unlock_kernel();
return error;
}
@@ -1491,13 +1479,9 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
attr.ia_mode = S_IFLNK | S_IRWXUGO;
attr.ia_valid = ATTR_MODE;
- lock_kernel();
-
page = alloc_page(GFP_HIGHUSER);
- if (!page) {
- unlock_kernel();
+ if (!page)
return -ENOMEM;
- }
kaddr = kmap_atomic(page, KM_USER0);
memcpy(kaddr, symname, pathlen);
@@ -1512,7 +1496,6 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
dentry->d_name.name, symname, error);
d_drop(dentry);
__free_page(page);
- unlock_kernel();
return error;
}
@@ -1530,7 +1513,6 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
} else
__free_page(page);
- unlock_kernel();
return 0;
}
@@ -1544,14 +1526,12 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
dentry->d_parent->d_name.name, dentry->d_name.name);
- lock_kernel();
d_drop(dentry);
error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
if (error == 0) {
atomic_inc(&inode->i_count);
d_add(dentry, inode);
}
- unlock_kernel();
return error;
}
@@ -1591,7 +1571,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* To prevent any new references to the target during the rename,
* we unhash the dentry and free the inode in advance.
*/
- lock_kernel();
if (!d_unhashed(new_dentry)) {
d_drop(new_dentry);
rehash = new_dentry;
@@ -1635,7 +1614,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* dentry still busy? */
goto out;
} else
- drop_nlink(new_inode);
+ nfs_drop_nlink(new_inode);
go_ahead:
/*
@@ -1669,7 +1648,6 @@ out:
/* new dentry created? */
if (dentry)
dput(dentry);
- unlock_kernel();
return error;
}
@@ -1962,8 +1940,6 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
}
force_lookup:
- lock_kernel();
-
if (!NFS_PROTO(inode)->access)
goto out_notsup;
@@ -1973,7 +1949,6 @@ force_lookup:
put_rpccred(cred);
} else
res = PTR_ERR(cred);
- unlock_kernel();
out:
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res);
@@ -1982,7 +1957,6 @@ out_notsup:
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (res == 0)
res = generic_permission(inode, mask, NULL);
- unlock_kernel();
goto out;
}
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 4757a2b326a..08f6b040d28 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -890,7 +890,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
count = iov_length(iov, nr_segs);
nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
- dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n",
+ dfprintk(FILE, "NFS: direct read(%s/%s, %zd@%Ld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name,
count, (long long) pos);
@@ -947,7 +947,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
count = iov_length(iov, nr_segs);
nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
- dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n",
+ dfprintk(FILE, "NFS: direct write(%s/%s, %zd@%Ld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name,
count, (long long) pos);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 4e98a56a177..78460657f5c 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -50,7 +50,7 @@ static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
static int nfs_file_flush(struct file *, fl_owner_t id);
-static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
+static int nfs_file_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
@@ -72,7 +72,7 @@ const struct file_operations nfs_file_operations = {
.open = nfs_file_open,
.flush = nfs_file_flush,
.release = nfs_file_release,
- .fsync = nfs_fsync,
+ .fsync = nfs_file_fsync,
.lock = nfs_lock,
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
@@ -119,25 +119,33 @@ nfs_file_open(struct inode *inode, struct file *filp)
{
int res;
+ dprintk("NFS: open file(%s/%s)\n",
+ filp->f_path.dentry->d_parent->d_name.name,
+ filp->f_path.dentry->d_name.name);
+
res = nfs_check_flags(filp->f_flags);
if (res)
return res;
nfs_inc_stats(inode, NFSIOS_VFSOPEN);
- lock_kernel();
- res = NFS_PROTO(inode)->file_open(inode, filp);
- unlock_kernel();
+ res = nfs_open(inode, filp);
return res;
}
static int
nfs_file_release(struct inode *inode, struct file *filp)
{
+ struct dentry *dentry = filp->f_path.dentry;
+
+ dprintk("NFS: release(%s/%s)\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+
/* Ensure that dirty pages are flushed out with the right creds */
if (filp->f_mode & FMODE_WRITE)
- nfs_wb_all(filp->f_path.dentry->d_inode);
+ nfs_wb_all(dentry->d_inode);
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
- return NFS_PROTO(inode)->file_release(inode, filp);
+ return nfs_release(inode, filp);
}
/**
@@ -171,6 +179,12 @@ force_reval:
static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
{
loff_t loff;
+
+ dprintk("NFS: llseek file(%s/%s, %lld, %d)\n",
+ filp->f_path.dentry->d_parent->d_name.name,
+ filp->f_path.dentry->d_name.name,
+ offset, origin);
+
/* origin == SEEK_END => we must revalidate the cached file length */
if (origin == SEEK_END) {
struct inode *inode = filp->f_mapping->host;
@@ -185,7 +199,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
}
/*
- * Helper for nfs_file_flush() and nfs_fsync()
+ * Helper for nfs_file_flush() and nfs_file_fsync()
*
* Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
* disk, but it retrieves and clears ctx->error after synching, despite
@@ -211,16 +225,18 @@ static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
/*
* Flush all dirty pages, and check for write errors.
- *
*/
static int
nfs_file_flush(struct file *file, fl_owner_t id)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
- struct inode *inode = file->f_path.dentry->d_inode;
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *inode = dentry->d_inode;
int status;
- dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
+ dprintk("NFS: flush(%s/%s)\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
if ((file->f_mode & FMODE_WRITE) == 0)
return 0;
@@ -245,7 +261,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
if (iocb->ki_filp->f_flags & O_DIRECT)
return nfs_file_direct_read(iocb, iov, nr_segs, pos);
- dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
+ dprintk("NFS: read(%s/%s, %lu@%lu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long) pos);
@@ -265,7 +281,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
struct inode *inode = dentry->d_inode;
ssize_t res;
- dfprintk(VFS, "nfs: splice_read(%s/%s, %lu@%Lu)\n",
+ dprintk("NFS: splice_read(%s/%s, %lu@%Lu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long long) *ppos);
@@ -282,7 +298,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
struct inode *inode = dentry->d_inode;
int status;
- dfprintk(VFS, "nfs: mmap(%s/%s)\n",
+ dprintk("NFS: mmap(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
status = nfs_revalidate_mapping(inode, file->f_mapping);
@@ -300,12 +316,14 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
* whether any write errors occurred for this process.
*/
static int
-nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = dentry->d_inode;
- dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
+ dprintk("NFS: fsync file(%s/%s) datasync %d\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ datasync);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
return nfs_do_fsync(ctx, inode);
@@ -328,6 +346,11 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
struct page *page;
index = pos >> PAGE_CACHE_SHIFT;
+ dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)\n",
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name,
+ mapping->host->i_ino, len, (long long) pos);
+
page = __grab_cache_page(mapping, index);
if (!page)
return -ENOMEM;
@@ -348,9 +371,32 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
int status;
- lock_kernel();
+ dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n",
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name,
+ mapping->host->i_ino, len, (long long) pos);
+
+ /*
+ * Zero any uninitialised parts of the page, and then mark the page
+ * as up to date if it turns out that we're extending the file.
+ */
+ if (!PageUptodate(page)) {
+ unsigned pglen = nfs_page_length(page);
+ unsigned end = offset + len;
+
+ if (pglen == 0) {
+ zero_user_segments(page, 0, offset,
+ end, PAGE_CACHE_SIZE);
+ SetPageUptodate(page);
+ } else if (end >= pglen) {
+ zero_user_segment(page, end, PAGE_CACHE_SIZE);
+ if (offset == 0)
+ SetPageUptodate(page);
+ } else
+ zero_user_segment(page, pglen, PAGE_CACHE_SIZE);
+ }
+
status = nfs_updatepage(file, page, offset, copied);
- unlock_kernel();
unlock_page(page);
page_cache_release(page);
@@ -362,6 +408,8 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
static void nfs_invalidate_page(struct page *page, unsigned long offset)
{
+ dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset);
+
if (offset != 0)
return;
/* Cancel any unstarted writes on this page */
@@ -370,13 +418,20 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
static int nfs_release_page(struct page *page, gfp_t gfp)
{
+ dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
+
/* If PagePrivate() is set, then the page is not freeable */
return 0;
}
static int nfs_launder_page(struct page *page)
{
- return nfs_wb_page(page->mapping->host, page);
+ struct inode *inode = page->mapping->host;
+
+ dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
+ inode->i_ino, (long long)page_offset(page));
+
+ return nfs_wb_page(inode, page);
}
const struct address_space_operations nfs_file_aops = {
@@ -396,13 +451,19 @@ const struct address_space_operations nfs_file_aops = {
static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
{
struct file *filp = vma->vm_file;
+ struct dentry *dentry = filp->f_path.dentry;
unsigned pagelen;
int ret = -EINVAL;
struct address_space *mapping;
+ dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ filp->f_mapping->host->i_ino,
+ (long long)page_offset(page));
+
lock_page(page);
mapping = page->mapping;
- if (mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping)
+ if (mapping != dentry->d_inode->i_mapping)
goto out_unlock;
ret = 0;
@@ -450,9 +511,9 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
if (iocb->ki_filp->f_flags & O_DIRECT)
return nfs_file_direct_write(iocb, iov, nr_segs, pos);
- dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
+ dprintk("NFS: write(%s/%s, %lu@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- inode->i_ino, (unsigned long) count, (long long) pos);
+ (unsigned long) count, (long long) pos);
result = -EBUSY;
if (IS_SWAPFILE(inode))
@@ -586,7 +647,8 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
* This makes locking act as a cache coherency point.
*/
nfs_sync_mapping(filp->f_mapping);
- nfs_zap_caches(inode);
+ if (!nfs_have_delegation(inode, FMODE_READ))
+ nfs_zap_caches(inode);
out:
return status;
}
@@ -596,23 +658,35 @@ out:
*/
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{
- struct inode * inode = filp->f_mapping->host;
+ struct inode *inode = filp->f_mapping->host;
+ int ret = -ENOLCK;
- dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
- inode->i_sb->s_id, inode->i_ino,
+ dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n",
+ filp->f_path.dentry->d_parent->d_name.name,
+ filp->f_path.dentry->d_name.name,
fl->fl_type, fl->fl_flags,
(long long)fl->fl_start, (long long)fl->fl_end);
+
nfs_inc_stats(inode, NFSIOS_VFSLOCK);
/* No mandatory locks over NFS */
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
- return -ENOLCK;
+ goto out_err;
+
+ if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
+ ret = NFS_PROTO(inode)->lock_check_bounds(fl);
+ if (ret < 0)
+ goto out_err;
+ }
if (IS_GETLK(cmd))
- return do_getlk(filp, cmd, fl);
- if (fl->fl_type == F_UNLCK)
- return do_unlk(filp, cmd, fl);
- return do_setlk(filp, cmd, fl);
+ ret = do_getlk(filp, cmd, fl);
+ else if (fl->fl_type == F_UNLCK)
+ ret = do_unlk(filp, cmd, fl);
+ else
+ ret = do_setlk(filp, cmd, fl);
+out_err:
+ return ret;
}
/*
@@ -620,9 +694,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
*/
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
{
- dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
- filp->f_path.dentry->d_inode->i_sb->s_id,
- filp->f_path.dentry->d_inode->i_ino,
+ dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
+ filp->f_path.dentry->d_parent->d_name.name,
+ filp->f_path.dentry->d_name.name,
fl->fl_type, fl->fl_flags);
/*
@@ -645,12 +719,15 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
return do_setlk(filp, cmd, fl);
}
+/*
+ * There is no protocol support for leases, so we have no way to implement
+ * them correctly in the face of opens by other clients.
+ */
static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
{
- /*
- * There is no protocol support for leases, so we have no way
- * to implement them correctly in the face of opens by other
- * clients.
- */
+ dprintk("NFS: setlease(%s/%s, arg=%ld)\n",
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name, arg);
+
return -EINVAL;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 596c5d8e86f..df23f987da6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -57,8 +57,6 @@ static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
static void nfs_invalidate_inode(struct inode *);
static int nfs_update_inode(struct inode *, struct nfs_fattr *);
-static void nfs_zap_acl_cache(struct inode *);
-
static struct kmem_cache * nfs_inode_cachep;
static inline unsigned long
@@ -167,7 +165,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
}
}
-static void nfs_zap_acl_cache(struct inode *inode)
+void nfs_zap_acl_cache(struct inode *inode)
{
void (*clear_acl_cache)(struct inode *);
@@ -347,7 +345,7 @@ out_no_inode:
goto out;
}
-#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET)
+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
int
nfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -369,10 +367,9 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
/* Optimization: if the end result is no change, don't RPC */
attr->ia_valid &= NFS_VALID_ATTRS;
- if (attr->ia_valid == 0)
+ if ((attr->ia_valid & ~ATTR_FILE) == 0)
return 0;
- lock_kernel();
/* Write all dirty data */
if (S_ISREG(inode->i_mode)) {
filemap_write_and_wait(inode->i_mapping);
@@ -386,11 +383,66 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
if (error == 0)
nfs_refresh_inode(inode, &fattr);
- unlock_kernel();
return error;
}
/**
+ * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall
+ * @inode: inode of the file used
+ * @offset: file offset to start truncating
+ *
+ * This is a copy of the common vmtruncate, but with the locking
+ * corrected to take into account the fact that NFS requires
+ * inode->i_size to be updated under the inode->i_lock.
+ */
+static int nfs_vmtruncate(struct inode * inode, loff_t offset)
+{
+ if (i_size_read(inode) < offset) {
+ unsigned long limit;
+
+ limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit != RLIM_INFINITY && offset > limit)
+ goto out_sig;
+ if (offset > inode->i_sb->s_maxbytes)
+ goto out_big;
+ spin_lock(&inode->i_lock);
+ i_size_write(inode, offset);
+ spin_unlock(&inode->i_lock);
+ } else {
+ struct address_space *mapping = inode->i_mapping;
+
+ /*
+ * truncation of in-use swapfiles is disallowed - it would
+ * cause subsequent swapout to scribble on the now-freed
+ * blocks.
+ */
+ if (IS_SWAPFILE(inode))
+ return -ETXTBSY;
+ spin_lock(&inode->i_lock);
+ i_size_write(inode, offset);
+ spin_unlock(&inode->i_lock);
+
+ /*
+ * unmap_mapping_range is called twice, first simply for
+ * efficiency so that truncate_inode_pages does fewer
+ * single-page unmaps. However after this first call, and
+ * before truncate_inode_pages finishes, it is possible for
+ * private pages to be COWed, which remain after
+ * truncate_inode_pages finishes, hence the second
+ * unmap_mapping_range call must be made for correctness.
+ */
+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+ truncate_inode_pages(mapping, offset);
+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+ }
+ return 0;
+out_sig:
+ send_sig(SIGXFSZ, current, 0);
+out_big:
+ return -EFBIG;
+}
+
+/**
* nfs_setattr_update_inode - Update inode metadata after a setattr call.
* @inode: pointer to struct inode
* @attr: pointer to struct iattr
@@ -416,8 +468,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
}
if ((attr->ia_valid & ATTR_SIZE) != 0) {
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
- inode->i_size = attr->ia_size;
- vmtruncate(inode, attr->ia_size);
+ nfs_vmtruncate(inode, attr->ia_size);
}
}
@@ -647,7 +698,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
inode->i_sb->s_id, (long long)NFS_FILEID(inode));
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
- lock_kernel();
if (is_bad_inode(inode))
goto out_nowait;
if (NFS_STALE(inode))
@@ -696,7 +746,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
nfs_wake_up_inode(inode);
out_nowait:
- unlock_kernel();
return status;
}
@@ -831,9 +880,9 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
}
- if (inode->i_size == nfs_size_to_loff_t(fattr->pre_size) &&
+ if (i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) &&
nfsi->npages == 0)
- inode->i_size = nfs_size_to_loff_t(fattr->size);
+ i_size_write(inode, nfs_size_to_loff_t(fattr->size));
}
}
@@ -974,7 +1023,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
(fattr->valid & NFS_ATTR_WCC) == 0) {
memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
- fattr->pre_size = inode->i_size;
+ fattr->pre_size = i_size_read(inode);
fattr->valid |= NFS_ATTR_WCC;
}
return nfs_post_op_update_inode(inode, fattr);
@@ -1059,7 +1108,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Do we perhaps have any outstanding writes, or has
* the file grown beyond our last write? */
if (nfsi->npages == 0 || new_isize > cur_isize) {
- inode->i_size = new_isize;
+ i_size_write(inode, new_isize);
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
}
dprintk("NFS: isize change on server for file %s/%ld\n",
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 04ae867dddb..24241fcbb98 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -150,6 +150,7 @@ extern void nfs_clear_inode(struct inode *);
#ifdef CONFIG_NFS_V4
extern void nfs4_clear_inode(struct inode *);
#endif
+void nfs_zap_acl_cache(struct inode *inode);
/* super.c */
extern struct file_system_type nfs_xdev_fs_type;
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h
index 6350ecbde58..a3695281003 100644
--- a/fs/nfs/iostat.h
+++ b/fs/nfs/iostat.h
@@ -5,135 +5,41 @@
*
* Copyright (C) 2005, 2006 Chuck Lever <cel@netapp.com>
*
- * NFS client per-mount statistics provide information about the health of
- * the NFS client and the health of each NFS mount point. Generally these
- * are not for detailed problem diagnosis, but simply to indicate that there
- * is a problem.
- *
- * These counters are not meant to be human-readable, but are meant to be
- * integrated into system monitoring tools such as "sar" and "iostat". As
- * such, the counters are sampled by the tools over time, and are never
- * zeroed after a file system is mounted. Moving averages can be computed
- * by the tools by taking the difference between two instantaneous samples
- * and dividing that by the time between the samples.
*/
#ifndef _NFS_IOSTAT
#define _NFS_IOSTAT
-#define NFS_IOSTAT_VERS "1.0"
-
-/*
- * NFS byte counters
- *
- * 1. SERVER - the number of payload bytes read from or written to the
- * server by the NFS client via an NFS READ or WRITE request.
- *
- * 2. NORMAL - the number of bytes read or written by applications via
- * the read(2) and write(2) system call interfaces.
- *
- * 3. DIRECT - the number of bytes read or written from files opened
- * with the O_DIRECT flag.
- *
- * These counters give a view of the data throughput into and out of the NFS
- * client. Comparing the number of bytes requested by an application with the
- * number of bytes the client requests from the server can provide an
- * indication of client efficiency (per-op, cache hits, etc).
- *
- * These counters can also help characterize which access methods are in
- * use. DIRECT by itself shows whether there is any O_DIRECT traffic.
- * NORMAL + DIRECT shows how much data is going through the system call
- * interface. A large amount of SERVER traffic without much NORMAL or
- * DIRECT traffic shows that applications are using mapped files.
- *
- * NFS page counters
- *
- * These count the number of pages read or written via nfs_readpage(),
- * nfs_readpages(), or their write equivalents.
- */
-enum nfs_stat_bytecounters {
- NFSIOS_NORMALREADBYTES = 0,
- NFSIOS_NORMALWRITTENBYTES,
- NFSIOS_DIRECTREADBYTES,
- NFSIOS_DIRECTWRITTENBYTES,
- NFSIOS_SERVERREADBYTES,
- NFSIOS_SERVERWRITTENBYTES,
- NFSIOS_READPAGES,
- NFSIOS_WRITEPAGES,
- __NFSIOS_BYTESMAX,
-};
-
-/*
- * NFS event counters
- *
- * These counters provide a low-overhead way of monitoring client activity
- * without enabling NFS trace debugging. The counters show the rate at
- * which VFS requests are made, and how often the client invalidates its
- * data and attribute caches. This allows system administrators to monitor
- * such things as how close-to-open is working, and answer questions such
- * as "why are there so many GETATTR requests on the wire?"
- *
- * They also count anamolous events such as short reads and writes, silly
- * renames due to close-after-delete, and operations that change the size
- * of a file (such operations can often be the source of data corruption
- * if applications aren't using file locking properly).
- */
-enum nfs_stat_eventcounters {
- NFSIOS_INODEREVALIDATE = 0,
- NFSIOS_DENTRYREVALIDATE,
- NFSIOS_DATAINVALIDATE,
- NFSIOS_ATTRINVALIDATE,
- NFSIOS_VFSOPEN,
- NFSIOS_VFSLOOKUP,
- NFSIOS_VFSACCESS,
- NFSIOS_VFSUPDATEPAGE,
- NFSIOS_VFSREADPAGE,
- NFSIOS_VFSREADPAGES,
- NFSIOS_VFSWRITEPAGE,
- NFSIOS_VFSWRITEPAGES,
- NFSIOS_VFSGETDENTS,
- NFSIOS_VFSSETATTR,
- NFSIOS_VFSFLUSH,
- NFSIOS_VFSFSYNC,
- NFSIOS_VFSLOCK,
- NFSIOS_VFSRELEASE,
- NFSIOS_CONGESTIONWAIT,
- NFSIOS_SETATTRTRUNC,
- NFSIOS_EXTENDWRITE,
- NFSIOS_SILLYRENAME,
- NFSIOS_SHORTREAD,
- NFSIOS_SHORTWRITE,
- NFSIOS_DELAY,
- __NFSIOS_COUNTSMAX,
-};
-
-#ifdef __KERNEL__
-
#include <linux/percpu.h>
#include <linux/cache.h>
+#include <linux/nfs_iostat.h>
struct nfs_iostats {
unsigned long long bytes[__NFSIOS_BYTESMAX];
unsigned long events[__NFSIOS_COUNTSMAX];
} ____cacheline_aligned;
-static inline void nfs_inc_server_stats(struct nfs_server *server, enum nfs_stat_eventcounters stat)
+static inline void nfs_inc_server_stats(const struct nfs_server *server,
+ enum nfs_stat_eventcounters stat)
{
struct nfs_iostats *iostats;
int cpu;
cpu = get_cpu();
iostats = per_cpu_ptr(server->io_stats, cpu);
- iostats->events[stat] ++;
+ iostats->events[stat]++;
put_cpu_no_resched();
}
-static inline void nfs_inc_stats(struct inode *inode, enum nfs_stat_eventcounters stat)
+static inline void nfs_inc_stats(const struct inode *inode,
+ enum nfs_stat_eventcounters stat)
{
nfs_inc_server_stats(NFS_SERVER(inode), stat);
}
-static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat_bytecounters stat, unsigned long addend)
+static inline void nfs_add_server_stats(const struct nfs_server *server,
+ enum nfs_stat_bytecounters stat,
+ unsigned long addend)
{
struct nfs_iostats *iostats;
int cpu;
@@ -144,7 +50,9 @@ static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat
put_cpu_no_resched();
}
-static inline void nfs_add_stats(struct inode *inode, enum nfs_stat_bytecounters stat, unsigned long addend)
+static inline void nfs_add_stats(const struct inode *inode,
+ enum nfs_stat_bytecounters stat,
+ unsigned long addend)
{
nfs_add_server_stats(NFS_SERVER(inode), stat, addend);
}
@@ -160,5 +68,4 @@ static inline void nfs_free_iostats(struct nfs_iostats *stats)
free_percpu(stats);
}
-#endif
-#endif
+#endif /* _NFS_IOSTAT */
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 9b7362565c0..423842f51ac 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -5,6 +5,8 @@
#include <linux/posix_acl_xattr.h>
#include <linux/nfsacl.h>
+#include "internal.h"
+
#define NFSDBG_FACILITY NFSDBG_PROC
ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
@@ -205,6 +207,8 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
status = nfs_revalidate_inode(server, inode);
if (status < 0)
return ERR_PTR(status);
+ if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
+ nfs_zap_acl_cache(inode);
acl = nfs3_get_cached_acl(inode, type);
if (acl != ERR_PTR(-EAGAIN))
return acl;
@@ -319,9 +323,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
dprintk("NFS call setacl\n");
msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
status = rpc_call_sync(server->client_acl, &msg, 0);
- spin_lock(&inode->i_lock);
- NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
- spin_unlock(&inode->i_lock);
+ nfs_access_zap_cache(inode);
+ nfs_zap_acl_cache(inode);
dprintk("NFS reply setacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index c3523ad03ed..1e750e4574a 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -129,6 +129,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
int status;
dprintk("NFS call setattr\n");
+ if (sattr->ia_valid & ATTR_FILE)
+ msg.rpc_cred = nfs_file_cred(sattr->ia_file);
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status == 0)
@@ -248,6 +250,53 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page,
return status;
}
+struct nfs3_createdata {
+ struct rpc_message msg;
+ union {
+ struct nfs3_createargs create;
+ struct nfs3_mkdirargs mkdir;
+ struct nfs3_symlinkargs symlink;
+ struct nfs3_mknodargs mknod;
+ } arg;
+ struct nfs3_diropres res;
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
+ struct nfs_fattr dir_attr;
+};
+
+static struct nfs3_createdata *nfs3_alloc_createdata(void)
+{
+ struct nfs3_createdata *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data != NULL) {
+ data->msg.rpc_argp = &data->arg;
+ data->msg.rpc_resp = &data->res;
+ data->res.fh = &data->fh;
+ data->res.fattr = &data->fattr;
+ data->res.dir_attr = &data->dir_attr;
+ nfs_fattr_init(data->res.fattr);
+ nfs_fattr_init(data->res.dir_attr);
+ }
+ return data;
+}
+
+static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data)
+{
+ int status;
+
+ status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
+ nfs_post_op_update_inode(dir, data->res.dir_attr);
+ if (status == 0)
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ return status;
+}
+
+static void nfs3_free_createdata(struct nfs3_createdata *data)
+{
+ kfree(data);
+}
+
/*
* Create a regular file.
* For now, we don't implement O_EXCL.
@@ -256,70 +305,60 @@ static int
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags, struct nameidata *nd)
{
- struct nfs_fh fhandle;
- struct nfs_fattr fattr;
- struct nfs_fattr dir_attr;
- struct nfs3_createargs arg = {
- .fh = NFS_FH(dir),
- .name = dentry->d_name.name,
- .len = dentry->d_name.len,
- .sattr = sattr,
- };
- struct nfs3_diropres res = {
- .dir_attr = &dir_attr,
- .fh = &fhandle,
- .fattr = &fattr
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs3_procedures[NFS3PROC_CREATE],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
+ struct nfs3_createdata *data;
mode_t mode = sattr->ia_mode;
- int status;
+ int status = -ENOMEM;
dprintk("NFS call create %s\n", dentry->d_name.name);
- arg.createmode = NFS3_CREATE_UNCHECKED;
+
+ data = nfs3_alloc_createdata();
+ if (data == NULL)
+ goto out;
+
+ data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE];
+ data->arg.create.fh = NFS_FH(dir);
+ data->arg.create.name = dentry->d_name.name;
+ data->arg.create.len = dentry->d_name.len;
+ data->arg.create.sattr = sattr;
+
+ data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
if (flags & O_EXCL) {
- arg.createmode = NFS3_CREATE_EXCLUSIVE;
- arg.verifier[0] = jiffies;
- arg.verifier[1] = current->pid;
+ data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE;
+ data->arg.create.verifier[0] = jiffies;
+ data->arg.create.verifier[1] = current->pid;
}
sattr->ia_mode &= ~current->fs->umask;
-again:
- nfs_fattr_init(&dir_attr);
- nfs_fattr_init(&fattr);
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_refresh_inode(dir, &dir_attr);
+ for (;;) {
+ status = nfs3_do_create(dir, dentry, data);
- /* If the server doesn't support the exclusive creation semantics,
- * try again with simple 'guarded' mode. */
- if (status == -ENOTSUPP) {
- switch (arg.createmode) {
+ if (status != -ENOTSUPP)
+ break;
+ /* If the server doesn't support the exclusive creation
+ * semantics, try again with simple 'guarded' mode. */
+ switch (data->arg.create.createmode) {
case NFS3_CREATE_EXCLUSIVE:
- arg.createmode = NFS3_CREATE_GUARDED;
+ data->arg.create.createmode = NFS3_CREATE_GUARDED;
break;
case NFS3_CREATE_GUARDED:
- arg.createmode = NFS3_CREATE_UNCHECKED;
+ data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
break;
case NFS3_CREATE_UNCHECKED:
goto out;
}
- goto again;
+ nfs_fattr_init(data->res.dir_attr);
+ nfs_fattr_init(data->res.fattr);
}
- if (status == 0)
- status = nfs_instantiate(dentry, &fhandle, &fattr);
if (status != 0)
goto out;
/* When we created the file with exclusive semantics, make
* sure we set the attributes afterwards. */
- if (arg.createmode == NFS3_CREATE_EXCLUSIVE) {
+ if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) {
dprintk("NFS call setattr (post-create)\n");
if (!(sattr->ia_valid & ATTR_ATIME_SET))
@@ -330,14 +369,15 @@ again:
/* Note: we could use a guarded setattr here, but I'm
* not sure this buys us anything (and I'd have
* to revamp the NFSv3 XDR code) */
- status = nfs3_proc_setattr(dentry, &fattr, sattr);
- nfs_post_op_update_inode(dentry->d_inode, &fattr);
+ status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
+ nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
dprintk("NFS reply setattr (post-create): %d\n", status);
+ if (status != 0)
+ goto out;
}
- if (status != 0)
- goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
+ nfs3_free_createdata(data);
dprintk("NFS reply create: %d\n", status);
return status;
}
@@ -452,40 +492,28 @@ static int
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
unsigned int len, struct iattr *sattr)
{
- struct nfs_fh fhandle;
- struct nfs_fattr fattr, dir_attr;
- struct nfs3_symlinkargs arg = {
- .fromfh = NFS_FH(dir),
- .fromname = dentry->d_name.name,
- .fromlen = dentry->d_name.len,
- .pages = &page,
- .pathlen = len,
- .sattr = sattr
- };
- struct nfs3_diropres res = {
- .dir_attr = &dir_attr,
- .fh = &fhandle,
- .fattr = &fattr
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
- int status;
+ struct nfs3_createdata *data;
+ int status = -ENOMEM;
if (len > NFS3_MAXPATHLEN)
return -ENAMETOOLONG;
dprintk("NFS call symlink %s\n", dentry->d_name.name);
- nfs_fattr_init(&dir_attr);
- nfs_fattr_init(&fattr);
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_post_op_update_inode(dir, &dir_attr);
- if (status != 0)
+ data = nfs3_alloc_createdata();
+ if (data == NULL)
goto out;
- status = nfs_instantiate(dentry, &fhandle, &fattr);
+ data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK];
+ data->arg.symlink.fromfh = NFS_FH(dir);
+ data->arg.symlink.fromname = dentry->d_name.name;
+ data->arg.symlink.fromlen = dentry->d_name.len;
+ data->arg.symlink.pages = &page;
+ data->arg.symlink.pathlen = len;
+ data->arg.symlink.sattr = sattr;
+
+ status = nfs3_do_create(dir, dentry, data);
+
+ nfs3_free_createdata(data);
out:
dprintk("NFS reply symlink: %d\n", status);
return status;
@@ -494,42 +522,31 @@ out:
static int
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
{
- struct nfs_fh fhandle;
- struct nfs_fattr fattr, dir_attr;
- struct nfs3_mkdirargs arg = {
- .fh = NFS_FH(dir),
- .name = dentry->d_name.name,
- .len = dentry->d_name.len,
- .sattr = sattr
- };
- struct nfs3_diropres res = {
- .dir_attr = &dir_attr,
- .fh = &fhandle,
- .fattr = &fattr
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
+ struct nfs3_createdata *data;
int mode = sattr->ia_mode;
- int status;
+ int status = -ENOMEM;
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
sattr->ia_mode &= ~current->fs->umask;
- nfs_fattr_init(&dir_attr);
- nfs_fattr_init(&fattr);
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_post_op_update_inode(dir, &dir_attr);
- if (status != 0)
+ data = nfs3_alloc_createdata();
+ if (data == NULL)
goto out;
- status = nfs_instantiate(dentry, &fhandle, &fattr);
+
+ data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
+ data->arg.mkdir.fh = NFS_FH(dir);
+ data->arg.mkdir.name = dentry->d_name.name;
+ data->arg.mkdir.len = dentry->d_name.len;
+ data->arg.mkdir.sattr = sattr;
+
+ status = nfs3_do_create(dir, dentry, data);
if (status != 0)
goto out;
+
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
+ nfs3_free_createdata(data);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
@@ -615,52 +632,50 @@ static int
nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
dev_t rdev)
{
- struct nfs_fh fh;
- struct nfs_fattr fattr, dir_attr;
- struct nfs3_mknodargs arg = {
- .fh = NFS_FH(dir),
- .name = dentry->d_name.name,
- .len = dentry->d_name.len,
- .sattr = sattr,
- .rdev = rdev
- };
- struct nfs3_diropres res = {
- .dir_attr = &dir_attr,
- .fh = &fh,
- .fattr = &fattr
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
+ struct nfs3_createdata *data;
mode_t mode = sattr->ia_mode;
- int status;
-
- switch (sattr->ia_mode & S_IFMT) {
- case S_IFBLK: arg.type = NF3BLK; break;
- case S_IFCHR: arg.type = NF3CHR; break;
- case S_IFIFO: arg.type = NF3FIFO; break;
- case S_IFSOCK: arg.type = NF3SOCK; break;
- default: return -EINVAL;
- }
+ int status = -ENOMEM;
dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
MAJOR(rdev), MINOR(rdev));
sattr->ia_mode &= ~current->fs->umask;
- nfs_fattr_init(&dir_attr);
- nfs_fattr_init(&fattr);
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_post_op_update_inode(dir, &dir_attr);
- if (status != 0)
+ data = nfs3_alloc_createdata();
+ if (data == NULL)
goto out;
- status = nfs_instantiate(dentry, &fh, &fattr);
+
+ data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD];
+ data->arg.mknod.fh = NFS_FH(dir);
+ data->arg.mknod.name = dentry->d_name.name;
+ data->arg.mknod.len = dentry->d_name.len;
+ data->arg.mknod.sattr = sattr;
+ data->arg.mknod.rdev = rdev;
+
+ switch (sattr->ia_mode & S_IFMT) {
+ case S_IFBLK:
+ data->arg.mknod.type = NF3BLK;
+ break;
+ case S_IFCHR:
+ data->arg.mknod.type = NF3CHR;
+ break;
+ case S_IFIFO:
+ data->arg.mknod.type = NF3FIFO;
+ break;
+ case S_IFSOCK:
+ data->arg.mknod.type = NF3SOCK;
+ break;
+ default:
+ status = -EINVAL;
+ goto out;
+ }
+
+ status = nfs3_do_create(dir, dentry, data);
if (status != 0)
goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
+ nfs3_free_createdata(data);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
@@ -801,8 +816,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.write_done = nfs3_write_done,
.commit_setup = nfs3_proc_commit_setup,
.commit_done = nfs3_commit_done,
- .file_open = nfs_open,
- .file_release = nfs_release,
.lock = nfs3_proc_lock,
.clear_acl_cache = nfs3_forget_cached_acls,
};
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1293e0acd82..c910413eaec 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -451,9 +451,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
/* Save the delegation */
memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
rcu_read_unlock();
- lock_kernel();
ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
- unlock_kernel();
if (ret != 0)
goto out;
ret = -EAGAIN;
@@ -1139,8 +1137,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
return res;
}
-static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
- struct iattr *sattr, struct nfs4_state *state)
+static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, struct iattr *sattr,
+ struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_setattrargs arg = {
@@ -1154,9 +1153,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
.server = server,
};
struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
- .rpc_argp = &arg,
- .rpc_resp = &res,
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
+ .rpc_cred = cred,
};
unsigned long timestamp = jiffies;
int status;
@@ -1166,7 +1166,6 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
/* Use that stateid */
} else if (state != NULL) {
- msg.rpc_cred = state->owner->so_cred;
nfs4_copy_stateid(&arg.stateid, state, current->files);
} else
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
@@ -1177,15 +1176,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
return status;
}
-static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
- struct iattr *sattr, struct nfs4_state *state)
+static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+ struct nfs_fattr *fattr, struct iattr *sattr,
+ struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
- _nfs4_do_setattr(inode, fattr, sattr, state),
+ _nfs4_do_setattr(inode, cred, fattr, sattr, state),
&exception);
} while (exception.retry);
return err;
@@ -1647,29 +1647,25 @@ static int
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct iattr *sattr)
{
- struct rpc_cred *cred;
struct inode *inode = dentry->d_inode;
- struct nfs_open_context *ctx;
+ struct rpc_cred *cred = NULL;
struct nfs4_state *state = NULL;
int status;
nfs_fattr_init(fattr);
- cred = rpc_lookup_cred();
- if (IS_ERR(cred))
- return PTR_ERR(cred);
-
/* Search for an existing open(O_WRITE) file */
- ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
- if (ctx != NULL)
+ if (sattr->ia_valid & ATTR_FILE) {
+ struct nfs_open_context *ctx;
+
+ ctx = nfs_file_open_context(sattr->ia_file);
+ cred = ctx->cred;
state = ctx->state;
+ }
- status = nfs4_do_setattr(inode, fattr, sattr, state);
+ status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
if (status == 0)
nfs_setattr_update_inode(inode, sattr);
- if (ctx != NULL)
- put_nfs_open_context(ctx);
- put_rpccred(cred);
return status;
}
@@ -1897,17 +1893,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
goto out;
}
state = nfs4_do_open(dir, &path, flags, sattr, cred);
- put_rpccred(cred);
d_drop(dentry);
if (IS_ERR(state)) {
status = PTR_ERR(state);
- goto out;
+ goto out_putcred;
}
d_add(dentry, igrab(state->inode));
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (flags & O_EXCL) {
struct nfs_fattr fattr;
- status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
+ status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
if (status == 0)
nfs_setattr_update_inode(state->inode, sattr);
nfs_post_op_update_inode(state->inode, &fattr);
@@ -1916,6 +1911,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = nfs4_intent_set_file(nd, &path, state);
else
nfs4_close_sync(&path, state, flags);
+out_putcred:
+ put_rpccred(cred);
out:
return status;
}
@@ -2079,47 +2076,81 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
return err;
}
+struct nfs4_createdata {
+ struct rpc_message msg;
+ struct nfs4_create_arg arg;
+ struct nfs4_create_res res;
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
+ struct nfs_fattr dir_fattr;
+};
+
+static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
+ struct qstr *name, struct iattr *sattr, u32 ftype)
+{
+ struct nfs4_createdata *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data != NULL) {
+ struct nfs_server *server = NFS_SERVER(dir);
+
+ data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
+ data->msg.rpc_argp = &data->arg;
+ data->msg.rpc_resp = &data->res;
+ data->arg.dir_fh = NFS_FH(dir);
+ data->arg.server = server;
+ data->arg.name = name;
+ data->arg.attrs = sattr;
+ data->arg.ftype = ftype;
+ data->arg.bitmask = server->attr_bitmask;
+ data->res.server = server;
+ data->res.fh = &data->fh;
+ data->res.fattr = &data->fattr;
+ data->res.dir_fattr = &data->dir_fattr;
+ nfs_fattr_init(data->res.fattr);
+ nfs_fattr_init(data->res.dir_fattr);
+ }
+ return data;
+}
+
+static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
+{
+ int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
+ if (status == 0) {
+ update_changeattr(dir, &data->res.dir_cinfo);
+ nfs_post_op_update_inode(dir, data->res.dir_fattr);
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ }
+ return status;
+}
+
+static void nfs4_free_createdata(struct nfs4_createdata *data)
+{
+ kfree(data);
+}
+
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct page *page, unsigned int len, struct iattr *sattr)
{
- struct nfs_server *server = NFS_SERVER(dir);
- struct nfs_fh fhandle;
- struct nfs_fattr fattr, dir_fattr;
- struct nfs4_create_arg arg = {
- .dir_fh = NFS_FH(dir),
- .server = server,
- .name = &dentry->d_name,
- .attrs = sattr,
- .ftype = NF4LNK,
- .bitmask = server->attr_bitmask,
- };
- struct nfs4_create_res res = {
- .server = server,
- .fh = &fhandle,
- .fattr = &fattr,
- .dir_fattr = &dir_fattr,
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
- int status;
+ struct nfs4_createdata *data;
+ int status = -ENAMETOOLONG;
if (len > NFS4_MAXPATHLEN)
- return -ENAMETOOLONG;
+ goto out;
- arg.u.symlink.pages = &page;
- arg.u.symlink.len = len;
- nfs_fattr_init(&fattr);
- nfs_fattr_init(&dir_fattr);
+ status = -ENOMEM;
+ data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
+ if (data == NULL)
+ goto out;
+
+ data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
+ data->arg.u.symlink.pages = &page;
+ data->arg.u.symlink.len = len;
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- if (!status) {
- update_changeattr(dir, &res.dir_cinfo);
- nfs_post_op_update_inode(dir, res.dir_fattr);
- status = nfs_instantiate(dentry, &fhandle, &fattr);
- }
+ status = nfs4_do_create(dir, dentry, data);
+
+ nfs4_free_createdata(data);
+out:
return status;
}
@@ -2140,39 +2171,17 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr)
{
- struct nfs_server *server = NFS_SERVER(dir);
- struct nfs_fh fhandle;
- struct nfs_fattr fattr, dir_fattr;
- struct nfs4_create_arg arg = {
- .dir_fh = NFS_FH(dir),
- .server = server,
- .name = &dentry->d_name,
- .attrs = sattr,
- .ftype = NF4DIR,
- .bitmask = server->attr_bitmask,
- };
- struct nfs4_create_res res = {
- .server = server,
- .fh = &fhandle,
- .fattr = &fattr,
- .dir_fattr = &dir_fattr,
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
- int status;
+ struct nfs4_createdata *data;
+ int status = -ENOMEM;
- nfs_fattr_init(&fattr);
- nfs_fattr_init(&dir_fattr);
-
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- if (!status) {
- update_changeattr(dir, &res.dir_cinfo);
- nfs_post_op_update_inode(dir, res.dir_fattr);
- status = nfs_instantiate(dentry, &fhandle, &fattr);
- }
+ data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
+ if (data == NULL)
+ goto out;
+
+ status = nfs4_do_create(dir, dentry, data);
+
+ nfs4_free_createdata(data);
+out:
return status;
}
@@ -2242,56 +2251,34 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev)
{
- struct nfs_server *server = NFS_SERVER(dir);
- struct nfs_fh fh;
- struct nfs_fattr fattr, dir_fattr;
- struct nfs4_create_arg arg = {
- .dir_fh = NFS_FH(dir),
- .server = server,
- .name = &dentry->d_name,
- .attrs = sattr,
- .bitmask = server->attr_bitmask,
- };
- struct nfs4_create_res res = {
- .server = server,
- .fh = &fh,
- .fattr = &fattr,
- .dir_fattr = &dir_fattr,
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
- .rpc_argp = &arg,
- .rpc_resp = &res,
- };
- int status;
- int mode = sattr->ia_mode;
-
- nfs_fattr_init(&fattr);
- nfs_fattr_init(&dir_fattr);
+ struct nfs4_createdata *data;
+ int mode = sattr->ia_mode;
+ int status = -ENOMEM;
BUG_ON(!(sattr->ia_valid & ATTR_MODE));
BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
+
+ data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
+ if (data == NULL)
+ goto out;
+
if (S_ISFIFO(mode))
- arg.ftype = NF4FIFO;
+ data->arg.ftype = NF4FIFO;
else if (S_ISBLK(mode)) {
- arg.ftype = NF4BLK;
- arg.u.device.specdata1 = MAJOR(rdev);
- arg.u.device.specdata2 = MINOR(rdev);
+ data->arg.ftype = NF4BLK;
+ data->arg.u.device.specdata1 = MAJOR(rdev);
+ data->arg.u.device.specdata2 = MINOR(rdev);
}
else if (S_ISCHR(mode)) {
- arg.ftype = NF4CHR;
- arg.u.device.specdata1 = MAJOR(rdev);
- arg.u.device.specdata2 = MINOR(rdev);
+ data->arg.ftype = NF4CHR;
+ data->arg.u.device.specdata1 = MAJOR(rdev);
+ data->arg.u.device.specdata2 = MINOR(rdev);
}
- else
- arg.ftype = NF4SOCK;
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- if (status == 0) {
- update_changeattr(dir, &res.dir_cinfo);
- nfs_post_op_update_inode(dir, res.dir_fattr);
- status = nfs_instantiate(dentry, &fh, &fattr);
- }
+ status = nfs4_do_create(dir, dentry, data);
+
+ nfs4_free_createdata(data);
+out:
return status;
}
@@ -2706,6 +2693,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
ret = nfs_revalidate_inode(server, inode);
if (ret < 0)
return ret;
+ if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
+ nfs_zap_acl_cache(inode);
ret = nfs4_read_cached_acl(inode, buf, buflen);
if (ret != -ENOENT)
return ret;
@@ -2733,7 +2722,8 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
nfs_inode_return_delegation(inode);
buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- nfs_zap_caches(inode);
+ nfs_access_zap_cache(inode);
+ nfs_zap_acl_cache(inode);
return ret;
}
@@ -2767,8 +2757,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
task->tk_status = 0;
return -EAGAIN;
case -NFS4ERR_DELAY:
- nfs_inc_server_stats((struct nfs_server *) server,
- NFSIOS_DELAY);
+ nfs_inc_server_stats(server, NFSIOS_DELAY);
case -NFS4ERR_GRACE:
rpc_delay(task, NFS4_POLL_RETRY_MAX);
task->tk_status = 0;
@@ -2933,7 +2922,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre
int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
{
- long timeout;
+ long timeout = 0;
int err;
do {
err = _nfs4_proc_setclientid_confirm(clp, cred);
@@ -3725,8 +3714,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.write_done = nfs4_write_done,
.commit_setup = nfs4_proc_commit_setup,
.commit_done = nfs4_commit_done,
- .file_open = nfs_open,
- .file_release = nfs_release,
.lock = nfs4_proc_lock,
.clear_acl_cache = nfs4_zap_acl_attr,
};
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 856a8934f61..401ef8b28f9 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -940,7 +940,6 @@ static int reclaimer(void *ptr)
allow_signal(SIGKILL);
/* Ensure exclusive access to NFSv4 state */
- lock_kernel();
down_write(&clp->cl_sem);
/* Are there any NFS mounts out there? */
if (list_empty(&clp->cl_superblocks))
@@ -1000,7 +999,6 @@ restart_loop:
nfs_delegation_reap_unclaimed(clp);
out:
up_write(&clp->cl_sem);
- unlock_kernel();
if (status == -NFS4ERR_CB_PATH_DOWN)
nfs_handle_cb_pathdown(clp);
nfs4_clear_recover_bit(clp);
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 531379d3682..46763d1cd39 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -1,6 +1,4 @@
/*
- * $Id: nfsroot.c,v 1.45 1998/03/07 10:44:46 mj Exp $
- *
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
* Allow an NFS filesystem to be mounted as root. The way this works is:
@@ -297,10 +295,10 @@ static int __init root_nfs_name(char *name)
nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
nfs_data.rsize = NFS_DEF_FILE_IO_SIZE;
nfs_data.wsize = NFS_DEF_FILE_IO_SIZE;
- nfs_data.acregmin = 3;
- nfs_data.acregmax = 60;
- nfs_data.acdirmin = 30;
- nfs_data.acdirmax = 60;
+ nfs_data.acregmin = NFS_DEF_ACREGMIN;
+ nfs_data.acregmax = NFS_DEF_ACREGMAX;
+ nfs_data.acdirmin = NFS_DEF_ACDIRMIN;
+ nfs_data.acdirmax = NFS_DEF_ACDIRMAX;
strcpy(buf, NFS_ROOT);
/* Process options received from the remote server */
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 03599bfe81c..4dbb84df1b6 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -129,6 +129,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
sattr->ia_mode &= S_IALLUGO;
dprintk("NFS call setattr\n");
+ if (sattr->ia_valid & ATTR_FILE)
+ msg.rpc_cred = nfs_file_cred(sattr->ia_file);
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status == 0)
@@ -598,6 +600,29 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
}
+/* Helper functions for NFS lock bounds checking */
+#define NFS_LOCK32_OFFSET_MAX ((__s32)0x7fffffffUL)
+static int nfs_lock_check_bounds(const struct file_lock *fl)
+{
+ __s32 start, end;
+
+ start = (__s32)fl->fl_start;
+ if ((loff_t)start != fl->fl_start)
+ goto out_einval;
+
+ if (fl->fl_end != OFFSET_MAX) {
+ end = (__s32)fl->fl_end;
+ if ((loff_t)end != fl->fl_end)
+ goto out_einval;
+ } else
+ end = NFS_LOCK32_OFFSET_MAX;
+
+ if (start < 0 || start > end)
+ goto out_einval;
+ return 0;
+out_einval:
+ return -EINVAL;
+}
const struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */
@@ -630,7 +655,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.write_setup = nfs_proc_write_setup,
.write_done = nfs_write_done,
.commit_setup = nfs_proc_commit_setup,
- .file_open = nfs_open,
- .file_release = nfs_release,
.lock = nfs_proc_lock,
+ .lock_check_bounds = nfs_lock_check_bounds,
};
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 614efeed543..1b94e3650f5 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -47,6 +47,7 @@
#include <linux/inet.h>
#include <linux/in6.h>
#include <net/ipv6.h>
+#include <linux/netdevice.h>
#include <linux/nfs_xdr.h>
#include <linux/magic.h>
#include <linux/parser.h>
@@ -65,7 +66,6 @@
enum {
/* Mount options that take no arguments */
Opt_soft, Opt_hard,
- Opt_intr, Opt_nointr,
Opt_posix, Opt_noposix,
Opt_cto, Opt_nocto,
Opt_ac, Opt_noac,
@@ -92,8 +92,8 @@ enum {
Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
Opt_addr, Opt_mountaddr, Opt_clientaddr,
- /* Mount options that are ignored */
- Opt_userspace, Opt_deprecated,
+ /* Special mount options */
+ Opt_userspace, Opt_deprecated, Opt_sloppy,
Opt_err
};
@@ -101,10 +101,14 @@ enum {
static match_table_t nfs_mount_option_tokens = {
{ Opt_userspace, "bg" },
{ Opt_userspace, "fg" },
+ { Opt_userspace, "retry=%s" },
+
+ { Opt_sloppy, "sloppy" },
+
{ Opt_soft, "soft" },
{ Opt_hard, "hard" },
- { Opt_intr, "intr" },
- { Opt_nointr, "nointr" },
+ { Opt_deprecated, "intr" },
+ { Opt_deprecated, "nointr" },
{ Opt_posix, "posix" },
{ Opt_noposix, "noposix" },
{ Opt_cto, "cto" },
@@ -136,7 +140,6 @@ static match_table_t nfs_mount_option_tokens = {
{ Opt_acdirmin, "acdirmin=%u" },
{ Opt_acdirmax, "acdirmax=%u" },
{ Opt_actimeo, "actimeo=%u" },
- { Opt_userspace, "retry=%u" },
{ Opt_namelen, "namlen=%u" },
{ Opt_mountport, "mountport=%u" },
{ Opt_mountvers, "mountvers=%u" },
@@ -207,6 +210,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static void nfs_kill_super(struct super_block *);
static void nfs_put_super(struct super_block *);
+static int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
static struct file_system_type nfs_fs_type = {
.owner = THIS_MODULE,
@@ -234,6 +238,7 @@ static const struct super_operations nfs_sops = {
.umount_begin = nfs_umount_begin,
.show_options = nfs_show_options,
.show_stats = nfs_show_stats,
+ .remount_fs = nfs_remount,
};
#ifdef CONFIG_NFS_V4
@@ -278,6 +283,7 @@ static const struct super_operations nfs4_sops = {
.umount_begin = nfs_umount_begin,
.show_options = nfs_show_options,
.show_stats = nfs_show_stats,
+ .remount_fs = nfs_remount,
};
#endif
@@ -368,8 +374,6 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
};
int error;
- lock_kernel();
-
error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
if (error < 0)
goto out_err;
@@ -401,12 +405,10 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_namelen = server->namelen;
- unlock_kernel();
return 0;
out_err:
dprintk("%s: statfs error = %d\n", __func__, -error);
- unlock_kernel();
return error;
}
@@ -514,13 +516,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
if (nfss->bsize != 0)
seq_printf(m, ",bsize=%u", nfss->bsize);
seq_printf(m, ",namlen=%u", nfss->namelen);
- if (nfss->acregmin != 3*HZ || showdefaults)
+ if (nfss->acregmin != NFS_DEF_ACREGMIN*HZ || showdefaults)
seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ);
- if (nfss->acregmax != 60*HZ || showdefaults)
+ if (nfss->acregmax != NFS_DEF_ACREGMAX*HZ || showdefaults)
seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ);
- if (nfss->acdirmin != 30*HZ || showdefaults)
+ if (nfss->acdirmin != NFS_DEF_ACDIRMIN*HZ || showdefaults)
seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ);
- if (nfss->acdirmax != 60*HZ || showdefaults)
+ if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults)
seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ);
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
if (nfss->flags & nfs_infop->flag)
@@ -702,49 +704,233 @@ static int nfs_verify_server_address(struct sockaddr *addr)
return 0;
}
+static void nfs_parse_ipv4_address(char *string, size_t str_len,
+ struct sockaddr *sap, size_t *addr_len)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ u8 *addr = (u8 *)&sin->sin_addr.s_addr;
+
+ if (str_len <= INET_ADDRSTRLEN) {
+ dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n",
+ (int)str_len, string);
+
+ sin->sin_family = AF_INET;
+ *addr_len = sizeof(*sin);
+ if (in4_pton(string, str_len, addr, '\0', NULL))
+ return;
+ }
+
+ sap->sa_family = AF_UNSPEC;
+ *addr_len = 0;
+}
+
+#define IPV6_SCOPE_DELIMITER '%'
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static void nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
+ const char *delim,
+ struct sockaddr_in6 *sin6)
+{
+ char *p;
+ size_t len;
+
+ if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
+ return ;
+ if (*delim != IPV6_SCOPE_DELIMITER)
+ return;
+
+ len = (string + str_len) - delim - 1;
+ p = kstrndup(delim + 1, len, GFP_KERNEL);
+ if (p) {
+ unsigned long scope_id = 0;
+ struct net_device *dev;
+
+ dev = dev_get_by_name(&init_net, p);
+ if (dev != NULL) {
+ scope_id = dev->ifindex;
+ dev_put(dev);
+ } else {
+ /* scope_id is set to zero on error */
+ strict_strtoul(p, 10, &scope_id);
+ }
+
+ kfree(p);
+ sin6->sin6_scope_id = scope_id;
+ dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
+ }
+}
+
+static void nfs_parse_ipv6_address(char *string, size_t str_len,
+ struct sockaddr *sap, size_t *addr_len)
+{
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+ u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
+ const char *delim;
+
+ if (str_len <= INET6_ADDRSTRLEN) {
+ dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n",
+ (int)str_len, string);
+
+ sin6->sin6_family = AF_INET6;
+ *addr_len = sizeof(*sin6);
+ if (in6_pton(string, str_len, addr, IPV6_SCOPE_DELIMITER, &delim)) {
+ nfs_parse_ipv6_scope_id(string, str_len, delim, sin6);
+ return;
+ }
+ }
+
+ sap->sa_family = AF_UNSPEC;
+ *addr_len = 0;
+}
+#else
+static void nfs_parse_ipv6_address(char *string, size_t str_len,
+ struct sockaddr *sap, size_t *addr_len)
+{
+ sap->sa_family = AF_UNSPEC;
+ *addr_len = 0;
+}
+#endif
+
/*
- * Parse string addresses passed in via a mount option,
- * and construct a sockaddr based on the result.
+ * Construct a sockaddr based on the contents of a string that contains
+ * an IP address in presentation format.
*
- * If address parsing fails, set the sockaddr's address
- * family to AF_UNSPEC to force nfs_verify_server_address()
- * to punt the mount.
+ * If there is a problem constructing the new sockaddr, set the address
+ * family to AF_UNSPEC.
*/
-static void nfs_parse_server_address(char *value,
- struct sockaddr *sap,
- size_t *len)
+static void nfs_parse_ip_address(char *string, size_t str_len,
+ struct sockaddr *sap, size_t *addr_len)
{
- if (strchr(value, ':')) {
- struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap;
- u8 *addr = (u8 *)&ap->sin6_addr.in6_u;
+ unsigned int i, colons;
- ap->sin6_family = AF_INET6;
- *len = sizeof(*ap);
- if (in6_pton(value, -1, addr, '\0', NULL))
- return;
- } else {
- struct sockaddr_in *ap = (struct sockaddr_in *)sap;
- u8 *addr = (u8 *)&ap->sin_addr.s_addr;
+ colons = 0;
+ for (i = 0; i < str_len; i++)
+ if (string[i] == ':')
+ colons++;
+
+ if (colons >= 2)
+ nfs_parse_ipv6_address(string, str_len, sap, addr_len);
+ else
+ nfs_parse_ipv4_address(string, str_len, sap, addr_len);
+}
+
+/*
+ * Sanity check the NFS transport protocol.
+ *
+ */
+static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
+{
+ switch (mnt->nfs_server.protocol) {
+ case XPRT_TRANSPORT_UDP:
+ case XPRT_TRANSPORT_TCP:
+ case XPRT_TRANSPORT_RDMA:
+ break;
+ default:
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ }
+}
+
+/*
+ * For text based NFSv2/v3 mounts, the mount protocol transport default
+ * settings should depend upon the specified NFS transport.
+ */
+static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
+{
+ nfs_validate_transport_protocol(mnt);
- ap->sin_family = AF_INET;
- *len = sizeof(*ap);
- if (in4_pton(value, -1, addr, '\0', NULL))
+ if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
+ mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
return;
+ switch (mnt->nfs_server.protocol) {
+ case XPRT_TRANSPORT_UDP:
+ mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ break;
+ case XPRT_TRANSPORT_TCP:
+ case XPRT_TRANSPORT_RDMA:
+ mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
}
+}
- sap->sa_family = AF_UNSPEC;
- *len = 0;
+/*
+ * Parse the value of the 'sec=' option.
+ *
+ * The flavor_len setting is for v4 mounts.
+ */
+static int nfs_parse_security_flavors(char *value,
+ struct nfs_parsed_mount_data *mnt)
+{
+ substring_t args[MAX_OPT_ARGS];
+
+ dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
+
+ switch (match_token(value, nfs_secflavor_tokens, args)) {
+ case Opt_sec_none:
+ mnt->auth_flavor_len = 0;
+ mnt->auth_flavors[0] = RPC_AUTH_NULL;
+ break;
+ case Opt_sec_sys:
+ mnt->auth_flavor_len = 0;
+ mnt->auth_flavors[0] = RPC_AUTH_UNIX;
+ break;
+ case Opt_sec_krb5:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
+ break;
+ case Opt_sec_krb5i:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
+ break;
+ case Opt_sec_krb5p:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
+ break;
+ case Opt_sec_lkey:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
+ break;
+ case Opt_sec_lkeyi:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
+ break;
+ case Opt_sec_lkeyp:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
+ break;
+ case Opt_sec_spkm:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
+ break;
+ case Opt_sec_spkmi:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
+ break;
+ case Opt_sec_spkmp:
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void nfs_parse_invalid_value(const char *option)
+{
+ dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option);
}
/*
* Error-check and convert a string of mount options from user space into
- * a data structure
+ * a data structure. The whole mount string is processed; bad options are
+ * skipped as they are encountered. If there were no errors, return 1;
+ * otherwise return 0 (zero).
*/
static int nfs_parse_mount_options(char *raw,
struct nfs_parsed_mount_data *mnt)
{
char *p, *string, *secdata;
- int rc;
+ int rc, sloppy = 0, errors = 0;
if (!raw) {
dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@@ -777,15 +963,16 @@ static int nfs_parse_mount_options(char *raw,
token = match_token(p, nfs_mount_option_tokens, args);
switch (token) {
+
+ /*
+ * boolean options: foo/nofoo
+ */
case Opt_soft:
mnt->flags |= NFS_MOUNT_SOFT;
break;
case Opt_hard:
mnt->flags &= ~NFS_MOUNT_SOFT;
break;
- case Opt_intr:
- case Opt_nointr:
- break;
case Opt_posix:
mnt->flags |= NFS_MOUNT_POSIX;
break;
@@ -819,20 +1006,14 @@ static int nfs_parse_mount_options(char *raw,
case Opt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- mnt->timeo = 7;
- mnt->retrans = 5;
break;
case Opt_tcp:
mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- mnt->timeo = 600;
- mnt->retrans = 2;
break;
case Opt_rdma:
mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
- mnt->timeo = 600;
- mnt->retrans = 2;
break;
case Opt_acl:
mnt->flags &= ~NFS_MOUNT_NOACL;
@@ -853,165 +1034,144 @@ static int nfs_parse_mount_options(char *raw,
mnt->flags |= NFS_MOUNT_UNSHARED;
break;
+ /*
+ * options that take numeric values
+ */
case Opt_port:
- if (match_int(args, &option))
- return 0;
- if (option < 0 || option > 65535)
- return 0;
- mnt->nfs_server.port = option;
+ if (match_int(args, &option) ||
+ option < 0 || option > USHORT_MAX) {
+ errors++;
+ nfs_parse_invalid_value("port");
+ } else
+ mnt->nfs_server.port = option;
break;
case Opt_rsize:
- if (match_int(args, &mnt->rsize))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("rsize");
+ } else
+ mnt->rsize = option;
break;
case Opt_wsize:
- if (match_int(args, &mnt->wsize))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("wsize");
+ } else
+ mnt->wsize = option;
break;
case Opt_bsize:
- if (match_int(args, &option))
- return 0;
- if (option < 0)
- return 0;
- mnt->bsize = option;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("bsize");
+ } else
+ mnt->bsize = option;
break;
case Opt_timeo:
- if (match_int(args, &mnt->timeo))
- return 0;
+ if (match_int(args, &option) || option <= 0) {
+ errors++;
+ nfs_parse_invalid_value("timeo");
+ } else
+ mnt->timeo = option;
break;
case Opt_retrans:
- if (match_int(args, &mnt->retrans))
- return 0;
+ if (match_int(args, &option) || option <= 0) {
+ errors++;
+ nfs_parse_invalid_value("retrans");
+ } else
+ mnt->retrans = option;
break;
case Opt_acregmin:
- if (match_int(args, &mnt->acregmin))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("acregmin");
+ } else
+ mnt->acregmin = option;
break;
case Opt_acregmax:
- if (match_int(args, &mnt->acregmax))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("acregmax");
+ } else
+ mnt->acregmax = option;
break;
case Opt_acdirmin:
- if (match_int(args, &mnt->acdirmin))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("acdirmin");
+ } else
+ mnt->acdirmin = option;
break;
case Opt_acdirmax:
- if (match_int(args, &mnt->acdirmax))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("acdirmax");
+ } else
+ mnt->acdirmax = option;
break;
case Opt_actimeo:
- if (match_int(args, &option))
- return 0;
- if (option < 0)
- return 0;
- mnt->acregmin =
- mnt->acregmax =
- mnt->acdirmin =
- mnt->acdirmax = option;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("actimeo");
+ } else
+ mnt->acregmin = mnt->acregmax =
+ mnt->acdirmin = mnt->acdirmax = option;
break;
case Opt_namelen:
- if (match_int(args, &mnt->namlen))
- return 0;
+ if (match_int(args, &option) || option < 0) {
+ errors++;
+ nfs_parse_invalid_value("namlen");
+ } else
+ mnt->namlen = option;
break;
case Opt_mountport:
- if (match_int(args, &option))
- return 0;
- if (option < 0 || option > 65535)
- return 0;
- mnt->mount_server.port = option;
+ if (match_int(args, &option) ||
+ option < 0 || option > USHORT_MAX) {
+ errors++;
+ nfs_parse_invalid_value("mountport");
+ } else
+ mnt->mount_server.port = option;
break;
case Opt_mountvers:
- if (match_int(args, &option))
- return 0;
- if (option < 0)
- return 0;
- mnt->mount_server.version = option;
+ if (match_int(args, &option) ||
+ option < NFS_MNT_VERSION ||
+ option > NFS_MNT3_VERSION) {
+ errors++;
+ nfs_parse_invalid_value("mountvers");
+ } else
+ mnt->mount_server.version = option;
break;
case Opt_nfsvers:
- if (match_int(args, &option))
- return 0;
+ if (match_int(args, &option)) {
+ errors++;
+ nfs_parse_invalid_value("nfsvers");
+ break;
+ }
switch (option) {
- case 2:
+ case NFS2_VERSION:
mnt->flags &= ~NFS_MOUNT_VER3;
break;
- case 3:
+ case NFS3_VERSION:
mnt->flags |= NFS_MOUNT_VER3;
break;
default:
- goto out_unrec_vers;
+ errors++;
+ nfs_parse_invalid_value("nfsvers");
}
break;
+ /*
+ * options that take text values
+ */
case Opt_sec:
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- token = match_token(string, nfs_secflavor_tokens, args);
+ rc = nfs_parse_security_flavors(string, mnt);
kfree(string);
-
- /*
- * The flags setting is for v2/v3. The flavor_len
- * setting is for v4. v2/v3 also need to know the
- * difference between NULL and UNIX.
- */
- switch (token) {
- case Opt_sec_none:
- mnt->flags &= ~NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 0;
- mnt->auth_flavors[0] = RPC_AUTH_NULL;
- break;
- case Opt_sec_sys:
- mnt->flags &= ~NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 0;
- mnt->auth_flavors[0] = RPC_AUTH_UNIX;
- break;
- case Opt_sec_krb5:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
- break;
- case Opt_sec_krb5i:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
- break;
- case Opt_sec_krb5p:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
- break;
- case Opt_sec_lkey:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
- break;
- case Opt_sec_lkeyi:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
- break;
- case Opt_sec_lkeyp:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
- break;
- case Opt_sec_spkm:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
- break;
- case Opt_sec_spkmi:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
- break;
- case Opt_sec_spkmp:
- mnt->flags |= NFS_MOUNT_SECFLAVOUR;
- mnt->auth_flavor_len = 1;
- mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
- break;
- default:
- goto out_unrec_sec;
+ if (!rc) {
+ errors++;
+ dfprintk(MOUNT, "NFS: unrecognized "
+ "security flavor\n");
}
break;
case Opt_proto:
@@ -1026,24 +1186,20 @@ static int nfs_parse_mount_options(char *raw,
case Opt_xprt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- mnt->timeo = 7;
- mnt->retrans = 5;
break;
case Opt_xprt_tcp:
mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- mnt->timeo = 600;
- mnt->retrans = 2;
break;
case Opt_xprt_rdma:
/* vector side protocols to TCP */
mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
- mnt->timeo = 600;
- mnt->retrans = 2;
break;
default:
- goto out_unrec_xprt;
+ errors++;
+ dfprintk(MOUNT, "NFS: unrecognized "
+ "transport protocol\n");
}
break;
case Opt_mountproto:
@@ -1063,16 +1219,19 @@ static int nfs_parse_mount_options(char *raw,
break;
case Opt_xprt_rdma: /* not used for side protocols */
default:
- goto out_unrec_xprt;
+ errors++;
+ dfprintk(MOUNT, "NFS: unrecognized "
+ "transport protocol\n");
}
break;
case Opt_addr:
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- nfs_parse_server_address(string, (struct sockaddr *)
- &mnt->nfs_server.address,
- &mnt->nfs_server.addrlen);
+ nfs_parse_ip_address(string, strlen(string),
+ (struct sockaddr *)
+ &mnt->nfs_server.address,
+ &mnt->nfs_server.addrlen);
kfree(string);
break;
case Opt_clientaddr:
@@ -1093,24 +1252,33 @@ static int nfs_parse_mount_options(char *raw,
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- nfs_parse_server_address(string, (struct sockaddr *)
- &mnt->mount_server.address,
- &mnt->mount_server.addrlen);
+ nfs_parse_ip_address(string, strlen(string),
+ (struct sockaddr *)
+ &mnt->mount_server.address,
+ &mnt->mount_server.addrlen);
kfree(string);
break;
+ /*
+ * Special options
+ */
+ case Opt_sloppy:
+ sloppy = 1;
+ dfprintk(MOUNT, "NFS: relaxing parsing rules\n");
+ break;
case Opt_userspace:
case Opt_deprecated:
+ dfprintk(MOUNT, "NFS: ignoring mount option "
+ "'%s'\n", p);
break;
default:
- goto out_unknown;
+ errors++;
+ dfprintk(MOUNT, "NFS: unrecognized mount option "
+ "'%s'\n", p);
}
}
- nfs_set_port((struct sockaddr *)&mnt->nfs_server.address,
- mnt->nfs_server.port);
-
return 1;
out_nomem:
@@ -1120,21 +1288,6 @@ out_security_failure:
free_secdata(secdata);
printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
return 0;
-out_unrec_vers:
- printk(KERN_INFO "NFS: unrecognized NFS version number\n");
- return 0;
-
-out_unrec_xprt:
- printk(KERN_INFO "NFS: unrecognized transport protocol\n");
- return 0;
-
-out_unrec_sec:
- printk(KERN_INFO "NFS: unrecognized security flavor\n");
- return 0;
-
-out_unknown:
- printk(KERN_INFO "NFS: unknown mount option: %s\n", p);
- return 0;
}
/*
@@ -1188,11 +1341,146 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
if (status == 0)
return 0;
- dfprintk(MOUNT, "NFS: unable to mount server %s, error %d",
+ dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
hostname, status);
return status;
}
+static int nfs_parse_simple_hostname(const char *dev_name,
+ char **hostname, size_t maxnamlen,
+ char **export_path, size_t maxpathlen)
+{
+ size_t len;
+ char *colon, *comma;
+
+ colon = strchr(dev_name, ':');
+ if (colon == NULL)
+ goto out_bad_devname;
+
+ len = colon - dev_name;
+ if (len > maxnamlen)
+ goto out_hostname;
+
+ /* N.B. caller will free nfs_server.hostname in all cases */
+ *hostname = kstrndup(dev_name, len, GFP_KERNEL);
+ if (!*hostname)
+ goto out_nomem;
+
+ /* kill possible hostname list: not supported */
+ comma = strchr(*hostname, ',');
+ if (comma != NULL) {
+ if (comma == *hostname)
+ goto out_bad_devname;
+ *comma = '\0';
+ }
+
+ colon++;
+ len = strlen(colon);
+ if (len > maxpathlen)
+ goto out_path;
+ *export_path = kstrndup(colon, len, GFP_KERNEL);
+ if (!*export_path)
+ goto out_nomem;
+
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
+ return 0;
+
+out_bad_devname:
+ dfprintk(MOUNT, "NFS: device name not in host:path format\n");
+ return -EINVAL;
+
+out_nomem:
+ dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
+ return -ENOMEM;
+
+out_hostname:
+ dfprintk(MOUNT, "NFS: server hostname too long\n");
+ return -ENAMETOOLONG;
+
+out_path:
+ dfprintk(MOUNT, "NFS: export pathname too long\n");
+ return -ENAMETOOLONG;
+}
+
+/*
+ * Hostname has square brackets around it because it contains one or
+ * more colons. We look for the first closing square bracket, and a
+ * colon must follow it.
+ */
+static int nfs_parse_protected_hostname(const char *dev_name,
+ char **hostname, size_t maxnamlen,
+ char **export_path, size_t maxpathlen)
+{
+ size_t len;
+ char *start, *end;
+
+ start = (char *)(dev_name + 1);
+
+ end = strchr(start, ']');
+ if (end == NULL)
+ goto out_bad_devname;
+ if (*(end + 1) != ':')
+ goto out_bad_devname;
+
+ len = end - start;
+ if (len > maxnamlen)
+ goto out_hostname;
+
+ /* N.B. caller will free nfs_server.hostname in all cases */
+ *hostname = kstrndup(start, len, GFP_KERNEL);
+ if (*hostname == NULL)
+ goto out_nomem;
+
+ end += 2;
+ len = strlen(end);
+ if (len > maxpathlen)
+ goto out_path;
+ *export_path = kstrndup(end, len, GFP_KERNEL);
+ if (!*export_path)
+ goto out_nomem;
+
+ return 0;
+
+out_bad_devname:
+ dfprintk(MOUNT, "NFS: device name not in host:path format\n");
+ return -EINVAL;
+
+out_nomem:
+ dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
+ return -ENOMEM;
+
+out_hostname:
+ dfprintk(MOUNT, "NFS: server hostname too long\n");
+ return -ENAMETOOLONG;
+
+out_path:
+ dfprintk(MOUNT, "NFS: export pathname too long\n");
+ return -ENAMETOOLONG;
+}
+
+/*
+ * Split "dev_name" into "hostname:export_path".
+ *
+ * The leftmost colon demarks the split between the server's hostname
+ * and the export path. If the hostname starts with a left square
+ * bracket, then it may contain colons.
+ *
+ * Note: caller frees hostname and export path, even on error.
+ */
+static int nfs_parse_devname(const char *dev_name,
+ char **hostname, size_t maxnamlen,
+ char **export_path, size_t maxpathlen)
+{
+ if (*dev_name == '[')
+ return nfs_parse_protected_hostname(dev_name,
+ hostname, maxnamlen,
+ export_path, maxpathlen);
+
+ return nfs_parse_simple_hostname(dev_name,
+ hostname, maxnamlen,
+ export_path, maxpathlen);
+}
+
/*
* Validate the NFS2/NFS3 mount data
* - fills in the mount root filehandle
@@ -1222,16 +1510,14 @@ static int nfs_validate_mount_data(void *options,
args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP);
args->rsize = NFS_MAX_FILE_IO_SIZE;
args->wsize = NFS_MAX_FILE_IO_SIZE;
- args->timeo = 600;
- args->retrans = 2;
- args->acregmin = 3;
- args->acregmax = 60;
- args->acdirmin = 30;
- args->acdirmax = 60;
+ args->acregmin = NFS_DEF_ACREGMIN;
+ args->acregmax = NFS_DEF_ACREGMAX;
+ args->acdirmin = NFS_DEF_ACDIRMIN;
+ args->acdirmax = NFS_DEF_ACDIRMAX;
args->mount_server.port = 0; /* autobind unless user sets port */
- args->mount_server.protocol = XPRT_TRANSPORT_UDP;
args->nfs_server.port = 0; /* autobind unless user sets port */
args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ args->auth_flavors[0] = RPC_AUTH_UNIX;
switch (data->version) {
case 1:
@@ -1289,7 +1575,9 @@ static int nfs_validate_mount_data(void *options,
args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
args->namlen = data->namlen;
args->bsize = data->bsize;
- args->auth_flavors[0] = data->pseudoflavor;
+
+ if (data->flags & NFS_MOUNT_SECFLAVOUR)
+ args->auth_flavors[0] = data->pseudoflavor;
if (!args->nfs_server.hostname)
goto out_nomem;
@@ -1321,8 +1609,6 @@ static int nfs_validate_mount_data(void *options,
break;
default: {
- unsigned int len;
- char *c;
int status;
if (nfs_parse_mount_options((char *)options, args) == 0)
@@ -1332,21 +1618,22 @@ static int nfs_validate_mount_data(void *options,
&args->nfs_server.address))
goto out_no_address;
- c = strchr(dev_name, ':');
- if (c == NULL)
- return -EINVAL;
- len = c - dev_name;
- /* N.B. caller will free nfs_server.hostname in all cases */
- args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
- if (!args->nfs_server.hostname)
- goto out_nomem;
+ nfs_set_port((struct sockaddr *)&args->nfs_server.address,
+ args->nfs_server.port);
- c++;
- if (strlen(c) > NFS_MAXPATHLEN)
- return -ENAMETOOLONG;
- args->nfs_server.export_path = c;
+ nfs_set_mount_transport_protocol(args);
+
+ status = nfs_parse_devname(dev_name,
+ &args->nfs_server.hostname,
+ PAGE_SIZE,
+ &args->nfs_server.export_path,
+ NFS_MAXPATHLEN);
+ if (!status)
+ status = nfs_try_mount(args, mntfh);
+
+ kfree(args->nfs_server.export_path);
+ args->nfs_server.export_path = NULL;
- status = nfs_try_mount(args, mntfh);
if (status)
return status;
@@ -1354,9 +1641,6 @@ static int nfs_validate_mount_data(void *options,
}
}
- if (!(args->flags & NFS_MOUNT_SECFLAVOUR))
- args->auth_flavors[0] = RPC_AUTH_UNIX;
-
#ifndef CONFIG_NFS_V3
if (args->flags & NFS_MOUNT_VER3)
goto out_v3_not_compiled;
@@ -1396,6 +1680,80 @@ out_invalid_fh:
return -EINVAL;
}
+static int
+nfs_compare_remount_data(struct nfs_server *nfss,
+ struct nfs_parsed_mount_data *data)
+{
+ if (data->flags != nfss->flags ||
+ data->rsize != nfss->rsize ||
+ data->wsize != nfss->wsize ||
+ data->retrans != nfss->client->cl_timeout->to_retries ||
+ data->auth_flavors[0] != nfss->client->cl_auth->au_flavor ||
+ data->acregmin != nfss->acregmin / HZ ||
+ data->acregmax != nfss->acregmax / HZ ||
+ data->acdirmin != nfss->acdirmin / HZ ||
+ data->acdirmax != nfss->acdirmax / HZ ||
+ data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
+ data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
+ memcmp(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
+ data->nfs_server.addrlen) != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+nfs_remount(struct super_block *sb, int *flags, char *raw_data)
+{
+ int error;
+ struct nfs_server *nfss = sb->s_fs_info;
+ struct nfs_parsed_mount_data *data;
+ struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
+ struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
+ u32 nfsvers = nfss->nfs_client->rpc_ops->version;
+
+ /*
+ * Userspace mount programs that send binary options generally send
+ * them populated with default values. We have no way to know which
+ * ones were explicitly specified. Fall back to legacy behavior and
+ * just return success.
+ */
+ if ((nfsvers == 4 && options4->version == 1) ||
+ (nfsvers <= 3 && options->version >= 1 &&
+ options->version <= 6))
+ return 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ /* fill out struct with values from existing mount */
+ data->flags = nfss->flags;
+ data->rsize = nfss->rsize;
+ data->wsize = nfss->wsize;
+ data->retrans = nfss->client->cl_timeout->to_retries;
+ data->auth_flavors[0] = nfss->client->cl_auth->au_flavor;
+ data->acregmin = nfss->acregmin / HZ;
+ data->acregmax = nfss->acregmax / HZ;
+ data->acdirmin = nfss->acdirmin / HZ;
+ data->acdirmax = nfss->acdirmax / HZ;
+ data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
+ data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
+ memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
+ data->nfs_server.addrlen);
+
+ /* overwrite those values with any that were specified */
+ error = nfs_parse_mount_options((char *)options, data);
+ if (error < 0)
+ goto out;
+
+ /* compare new mount options with old ones */
+ error = nfs_compare_remount_data(nfss, data);
+out:
+ kfree(data);
+ return error;
+}
+
/*
* Initialise the common bits of the superblock
*/
@@ -1811,14 +2169,13 @@ static int nfs4_validate_mount_data(void *options,
args->rsize = NFS_MAX_FILE_IO_SIZE;
args->wsize = NFS_MAX_FILE_IO_SIZE;
- args->timeo = 600;
- args->retrans = 2;
- args->acregmin = 3;
- args->acregmax = 60;
- args->acdirmin = 30;
- args->acdirmax = 60;
+ args->acregmin = NFS_DEF_ACREGMIN;
+ args->acregmax = NFS_DEF_ACREGMAX;
+ args->acdirmin = NFS_DEF_ACDIRMIN;
+ args->acdirmax = NFS_DEF_ACDIRMAX;
args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */
- args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ args->auth_flavors[0] = RPC_AUTH_UNIX;
+ args->auth_flavor_len = 0;
switch (data->version) {
case 1:
@@ -1834,18 +2191,13 @@ static int nfs4_validate_mount_data(void *options,
&args->nfs_server.address))
goto out_no_address;
- switch (data->auth_flavourlen) {
- case 0:
- args->auth_flavors[0] = RPC_AUTH_UNIX;
- break;
- case 1:
+ if (data->auth_flavourlen) {
+ if (data->auth_flavourlen > 1)
+ goto out_inval_auth;
if (copy_from_user(&args->auth_flavors[0],
data->auth_flavours,
sizeof(args->auth_flavors[0])))
return -EFAULT;
- break;
- default:
- goto out_inval_auth;
}
c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
@@ -1879,10 +2231,11 @@ static int nfs4_validate_mount_data(void *options,
args->acdirmin = data->acdirmin;
args->acdirmax = data->acdirmax;
args->nfs_server.protocol = data->proto;
+ nfs_validate_transport_protocol(args);
break;
default: {
- unsigned int len;
+ int status;
if (nfs_parse_mount_options((char *)options, args) == 0)
return -EINVAL;
@@ -1891,44 +2244,25 @@ static int nfs4_validate_mount_data(void *options,
&args->nfs_server.address))
return -EINVAL;
- switch (args->auth_flavor_len) {
- case 0:
- args->auth_flavors[0] = RPC_AUTH_UNIX;
- break;
- case 1:
- break;
- default:
- goto out_inval_auth;
- }
+ nfs_set_port((struct sockaddr *)&args->nfs_server.address,
+ args->nfs_server.port);
- /*
- * Split "dev_name" into "hostname:mntpath".
- */
- c = strchr(dev_name, ':');
- if (c == NULL)
- return -EINVAL;
- /* while calculating len, pretend ':' is '\0' */
- len = c - dev_name;
- if (len > NFS4_MAXNAMLEN)
- return -ENAMETOOLONG;
- /* N.B. caller will free nfs_server.hostname in all cases */
- args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
- if (!args->nfs_server.hostname)
- goto out_nomem;
-
- c++; /* step over the ':' */
- len = strlen(c);
- if (len > NFS4_MAXPATHLEN)
- return -ENAMETOOLONG;
- args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL);
- if (!args->nfs_server.export_path)
- goto out_nomem;
+ nfs_validate_transport_protocol(args);
- dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path);
+ if (args->auth_flavor_len > 1)
+ goto out_inval_auth;
if (args->client_address == NULL)
goto out_no_client_address;
+ status = nfs_parse_devname(dev_name,
+ &args->nfs_server.hostname,
+ NFS4_MAXNAMLEN,
+ &args->nfs_server.export_path,
+ NFS4_MAXPATHLEN);
+ if (status < 0)
+ return status;
+
break;
}
}
@@ -1944,10 +2278,6 @@ out_inval_auth:
data->auth_flavourlen);
return -EINVAL;
-out_nomem:
- dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n");
- return -ENOMEM;
-
out_no_address:
dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
return -EINVAL;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f333848fd3b..3229e217c77 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -34,9 +34,6 @@
/*
* Local function declarations
*/
-static struct nfs_page * nfs_update_request(struct nfs_open_context*,
- struct page *,
- unsigned int, unsigned int);
static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
struct inode *inode, int ioflags);
static void nfs_redirty_request(struct nfs_page *req);
@@ -136,16 +133,21 @@ static struct nfs_page *nfs_page_find_request(struct page *page)
static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
{
struct inode *inode = page->mapping->host;
- loff_t end, i_size = i_size_read(inode);
- pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
+ loff_t end, i_size;
+ pgoff_t end_index;
+ spin_lock(&inode->i_lock);
+ i_size = i_size_read(inode);
+ end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
if (i_size > 0 && page->index < end_index)
- return;
+ goto out;
end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
if (i_size >= end)
- return;
- nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
+ goto out;
i_size_write(inode, end);
+ nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
+out:
+ spin_unlock(&inode->i_lock);
}
/* A writeback failed: mark the page as bad, and invalidate the page cache */
@@ -169,29 +171,6 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int
SetPageUptodate(page);
}
-static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
- unsigned int offset, unsigned int count)
-{
- struct nfs_page *req;
- int ret;
-
- for (;;) {
- req = nfs_update_request(ctx, page, offset, count);
- if (!IS_ERR(req))
- break;
- ret = PTR_ERR(req);
- if (ret != -EBUSY)
- return ret;
- ret = nfs_wb_page(page->mapping->host, page);
- if (ret != 0)
- return ret;
- }
- /* Update file length */
- nfs_grow_file(page, offset, count);
- nfs_clear_page_tag_locked(req);
- return 0;
-}
-
static int wb_priority(struct writeback_control *wbc)
{
if (wbc->for_reclaim)
@@ -268,12 +247,9 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
return ret;
spin_lock(&inode->i_lock);
}
- if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
- /* This request is marked for commit */
+ if (test_bit(PG_CLEAN, &req->wb_flags)) {
spin_unlock(&inode->i_lock);
- nfs_clear_page_tag_locked(req);
- nfs_pageio_complete(pgio);
- return 0;
+ BUG();
}
if (nfs_set_page_writeback(page) != 0) {
spin_unlock(&inode->i_lock);
@@ -355,11 +331,19 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
/*
* Insert a write request into an inode
*/
-static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
+static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
{
struct nfs_inode *nfsi = NFS_I(inode);
int error;
+ error = radix_tree_preload(GFP_NOFS);
+ if (error != 0)
+ goto out;
+
+ /* Lock the request! */
+ nfs_lock_request_dontget(req);
+
+ spin_lock(&inode->i_lock);
error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
BUG_ON(error);
if (!nfsi->npages) {
@@ -373,6 +357,10 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
kref_get(&req->wb_kref);
radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
NFS_PAGE_TAG_LOCKED);
+ spin_unlock(&inode->i_lock);
+ radix_tree_preload_end();
+out:
+ return error;
}
/*
@@ -405,19 +393,6 @@ nfs_mark_request_dirty(struct nfs_page *req)
__set_page_dirty_nobuffers(req->wb_page);
}
-/*
- * Check if a request is dirty
- */
-static inline int
-nfs_dirty_request(struct nfs_page *req)
-{
- struct page *page = req->wb_page;
-
- if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags))
- return 0;
- return !PageWriteback(page);
-}
-
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
/*
* Add a request to the inode's commit list.
@@ -430,7 +405,7 @@ nfs_mark_request_commit(struct nfs_page *req)
spin_lock(&inode->i_lock);
nfsi->ncommit++;
- set_bit(PG_NEED_COMMIT, &(req)->wb_flags);
+ set_bit(PG_CLEAN, &(req)->wb_flags);
radix_tree_tag_set(&nfsi->nfs_page_tree,
req->wb_index,
NFS_PAGE_TAG_COMMIT);
@@ -440,6 +415,19 @@ nfs_mark_request_commit(struct nfs_page *req)
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
}
+static int
+nfs_clear_request_commit(struct nfs_page *req)
+{
+ struct page *page = req->wb_page;
+
+ if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
+ dec_zone_page_state(page, NR_UNSTABLE_NFS);
+ dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+ return 1;
+ }
+ return 0;
+}
+
static inline
int nfs_write_need_commit(struct nfs_write_data *data)
{
@@ -449,7 +437,7 @@ int nfs_write_need_commit(struct nfs_write_data *data)
static inline
int nfs_reschedule_unstable_write(struct nfs_page *req)
{
- if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
+ if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
nfs_mark_request_commit(req);
return 1;
}
@@ -465,6 +453,12 @@ nfs_mark_request_commit(struct nfs_page *req)
{
}
+static inline int
+nfs_clear_request_commit(struct nfs_page *req)
+{
+ return 0;
+}
+
static inline
int nfs_write_need_commit(struct nfs_write_data *data)
{
@@ -522,11 +516,8 @@ static void nfs_cancel_commit_list(struct list_head *head)
while(!list_empty(head)) {
req = nfs_list_entry(head->next);
- dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
- dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
- BDI_RECLAIMABLE);
nfs_list_remove_request(req);
- clear_bit(PG_NEED_COMMIT, &(req)->wb_flags);
+ nfs_clear_request_commit(req);
nfs_inode_remove_request(req);
nfs_unlock_request(req);
}
@@ -564,110 +555,124 @@ static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pg
#endif
/*
- * Try to update any existing write request, or create one if there is none.
- * In order to match, the request's credentials must match those of
- * the calling process.
+ * Search for an existing write request, and attempt to update
+ * it to reflect a new dirty region on a given page.
*
- * Note: Should always be called with the Page Lock held!
+ * If the attempt fails, then the existing request is flushed out
+ * to disk.
*/
-static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
- struct page *page, unsigned int offset, unsigned int bytes)
+static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
+ struct page *page,
+ unsigned int offset,
+ unsigned int bytes)
{
- struct address_space *mapping = page->mapping;
- struct inode *inode = mapping->host;
- struct nfs_page *req, *new = NULL;
- pgoff_t rqend, end;
+ struct nfs_page *req;
+ unsigned int rqend;
+ unsigned int end;
+ int error;
+
+ if (!PagePrivate(page))
+ return NULL;
end = offset + bytes;
+ spin_lock(&inode->i_lock);
for (;;) {
- /* Loop over all inode entries and see if we find
- * A request for the page we wish to update
+ req = nfs_page_find_request_locked(page);
+ if (req == NULL)
+ goto out_unlock;
+
+ rqend = req->wb_offset + req->wb_bytes;
+ /*
+ * Tell the caller to flush out the request if
+ * the offsets are non-contiguous.
+ * Note: nfs_flush_incompatible() will already
+ * have flushed out requests having wrong owners.
*/
- if (new) {
- if (radix_tree_preload(GFP_NOFS)) {
- nfs_release_request(new);
- return ERR_PTR(-ENOMEM);
- }
- }
+ if (offset > rqend
+ || end < req->wb_offset)
+ goto out_flushme;
- spin_lock(&inode->i_lock);
- req = nfs_page_find_request_locked(page);
- if (req) {
- if (!nfs_set_page_tag_locked(req)) {
- int error;
-
- spin_unlock(&inode->i_lock);
- error = nfs_wait_on_request(req);
- nfs_release_request(req);
- if (error < 0) {
- if (new) {
- radix_tree_preload_end();
- nfs_release_request(new);
- }
- return ERR_PTR(error);
- }
- continue;
- }
- spin_unlock(&inode->i_lock);
- if (new) {
- radix_tree_preload_end();
- nfs_release_request(new);
- }
+ if (nfs_set_page_tag_locked(req))
break;
- }
- if (new) {
- nfs_lock_request_dontget(new);
- nfs_inode_add_request(inode, new);
- spin_unlock(&inode->i_lock);
- radix_tree_preload_end();
- req = new;
- goto zero_page;
- }
+ /* The request is locked, so wait and then retry */
spin_unlock(&inode->i_lock);
-
- new = nfs_create_request(ctx, inode, page, offset, bytes);
- if (IS_ERR(new))
- return new;
+ error = nfs_wait_on_request(req);
+ nfs_release_request(req);
+ if (error != 0)
+ goto out_err;
+ spin_lock(&inode->i_lock);
}
- /* We have a request for our page.
- * If the creds don't match, or the
- * page addresses don't match,
- * tell the caller to wait on the conflicting
- * request.
- */
- rqend = req->wb_offset + req->wb_bytes;
- if (req->wb_context != ctx
- || req->wb_page != page
- || !nfs_dirty_request(req)
- || offset > rqend || end < req->wb_offset) {
- nfs_clear_page_tag_locked(req);
- return ERR_PTR(-EBUSY);
- }
+ if (nfs_clear_request_commit(req))
+ radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
+ req->wb_index, NFS_PAGE_TAG_COMMIT);
/* Okay, the request matches. Update the region */
if (offset < req->wb_offset) {
req->wb_offset = offset;
req->wb_pgbase = offset;
- req->wb_bytes = max(end, rqend) - req->wb_offset;
- goto zero_page;
}
-
if (end > rqend)
req->wb_bytes = end - req->wb_offset;
-
+ else
+ req->wb_bytes = rqend - req->wb_offset;
+out_unlock:
+ spin_unlock(&inode->i_lock);
return req;
-zero_page:
- /* If this page might potentially be marked as up to date,
- * then we need to zero any uninitalised data. */
- if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
- && !PageUptodate(req->wb_page))
- zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE);
+out_flushme:
+ spin_unlock(&inode->i_lock);
+ nfs_release_request(req);
+ error = nfs_wb_page(inode, page);
+out_err:
+ return ERR_PTR(error);
+}
+
+/*
+ * Try to update an existing write request, or create one if there is none.
+ *
+ * Note: Should always be called with the Page Lock held to prevent races
+ * if we have to add a new request. Also assumes that the caller has
+ * already called nfs_flush_incompatible() if necessary.
+ */
+static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
+ struct page *page, unsigned int offset, unsigned int bytes)
+{
+ struct inode *inode = page->mapping->host;
+ struct nfs_page *req;
+ int error;
+
+ req = nfs_try_to_update_request(inode, page, offset, bytes);
+ if (req != NULL)
+ goto out;
+ req = nfs_create_request(ctx, inode, page, offset, bytes);
+ if (IS_ERR(req))
+ goto out;
+ error = nfs_inode_add_request(inode, req);
+ if (error != 0) {
+ nfs_release_request(req);
+ req = ERR_PTR(error);
+ }
+out:
return req;
}
+static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
+ unsigned int offset, unsigned int count)
+{
+ struct nfs_page *req;
+
+ req = nfs_setup_write_request(ctx, page, offset, count);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ /* Update file length */
+ nfs_grow_file(page, offset, count);
+ nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
+ nfs_clear_page_tag_locked(req);
+ return 0;
+}
+
int nfs_flush_incompatible(struct file *file, struct page *page)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
@@ -685,8 +690,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
req = nfs_page_find_request(page);
if (req == NULL)
return 0;
- do_flush = req->wb_page != page || req->wb_context != ctx
- || !nfs_dirty_request(req);
+ do_flush = req->wb_page != page || req->wb_context != ctx;
nfs_release_request(req);
if (!do_flush)
return 0;
@@ -721,10 +725,10 @@ int nfs_updatepage(struct file *file, struct page *page,
nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
- dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
+ dprintk("NFS: nfs_updatepage(%s/%s %d@%lld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name, count,
- (long long)(page_offset(page) +offset));
+ (long long)(page_offset(page) + offset));
/* If we're not using byte range locks, and we know the page
* is up to date, it may be more efficient to extend the write
@@ -744,7 +748,7 @@ int nfs_updatepage(struct file *file, struct page *page,
else
__set_page_dirty_nobuffers(page);
- dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
+ dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n",
status, (long long)i_size_read(inode));
return status;
}
@@ -752,12 +756,7 @@ int nfs_updatepage(struct file *file, struct page *page,
static void nfs_writepage_release(struct nfs_page *req)
{
- if (PageError(req->wb_page)) {
- nfs_end_page_writeback(req->wb_page);
- nfs_inode_remove_request(req);
- } else if (!nfs_reschedule_unstable_write(req)) {
- /* Set the PG_uptodate flag */
- nfs_mark_uptodate(req->wb_page, req->wb_pgbase, req->wb_bytes);
+ if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) {
nfs_end_page_writeback(req->wb_page);
nfs_inode_remove_request(req);
} else
@@ -834,7 +833,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
NFS_PROTO(inode)->write_setup(data, &msg);
dprintk("NFS: %5u initiated write call "
- "(req %s/%Ld, %u bytes @ offset %Lu)\n",
+ "(req %s/%lld, %u bytes @ offset %llu)\n",
data->task.tk_pid,
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
@@ -978,13 +977,13 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
- struct nfs_page *req = data->req;
- dprintk("NFS: write (%s/%Ld %d@%Ld)",
- req->wb_context->path.dentry->d_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
- req->wb_bytes,
- (long long)req_offset(req));
+ dprintk("NFS: %5u write(%s/%lld %d@%lld)",
+ task->tk_pid,
+ data->req->wb_context->path.dentry->d_inode->i_sb->s_id,
+ (long long)
+ NFS_FILEID(data->req->wb_context->path.dentry->d_inode),
+ data->req->wb_bytes, (long long)req_offset(data->req));
nfs_writeback_done(task, data);
}
@@ -1058,7 +1057,8 @@ static void nfs_writeback_release_full(void *calldata)
nfs_list_remove_request(req);
- dprintk("NFS: write (%s/%Ld %d@%Ld)",
+ dprintk("NFS: %5u write (%s/%lld %d@%lld)",
+ data->task.tk_pid,
req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
@@ -1078,8 +1078,6 @@ static void nfs_writeback_release_full(void *calldata)
dprintk(" marked for commit\n");
goto next;
}
- /* Set the PG_uptodate flag? */
- nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
dprintk(" OK\n");
remove_request:
nfs_end_page_writeback(page);
@@ -1133,7 +1131,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
static unsigned long complain;
if (time_before(complain, jiffies)) {
- dprintk("NFS: faulty NFS server %s:"
+ dprintk("NFS: faulty NFS server %s:"
" (committed = %d) != (stable = %d)\n",
NFS_SERVER(data->inode)->nfs_client->cl_hostname,
resp->verf->committed, argp->stable);
@@ -1297,12 +1295,9 @@ static void nfs_commit_release(void *calldata)
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
- clear_bit(PG_NEED_COMMIT, &(req)->wb_flags);
- dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
- dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
- BDI_RECLAIMABLE);
+ nfs_clear_request_commit(req);
- dprintk("NFS: commit (%s/%Ld %d@%Ld)",
+ dprintk("NFS: commit (%s/%lld %d@%lld)",
req->wb_context->path.dentry->d_inode->i_sb->s_id,
(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
@@ -1318,9 +1313,6 @@ static void nfs_commit_release(void *calldata)
* returned by the server against all stored verfs. */
if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
/* We have a match */
- /* Set the PG_uptodate flag */
- nfs_mark_uptodate(req->wb_page, req->wb_pgbase,
- req->wb_bytes);
nfs_inode_remove_request(req);
dprintk(" OK\n");
goto next;
@@ -1479,7 +1471,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
req = nfs_page_find_request(page);
if (req == NULL)
goto out;
- if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
+ if (test_bit(PG_CLEAN, &req->wb_flags)) {
nfs_release_request(req);
break;
}
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 4d4760e687c..702fa577aa6 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -381,7 +381,7 @@ static int do_probe_callback(void *data)
.program = &cb_program,
.version = nfs_cb_version[1]->number,
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
- .flags = (RPC_CLNT_CREATE_NOPING),
+ .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
};
struct rpc_message msg = {
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 28fe8bae103..4eb75a88795 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -63,7 +63,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20080321
+#define ACPI_CA_VERSION 0x20080609
/*
* OS name, used for the _OS object. The _OS object is essentially obsolete,
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 788f8878201..f53faca8ec8 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -162,6 +162,7 @@ extern struct acpi_dmtable_info acpi_dm_table_info_dmar_hdr[];
extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[];
extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[];
extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar2[];
extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
extern struct acpi_dmtable_info acpi_dm_table_info_einj[];
extern struct acpi_dmtable_info acpi_dm_table_info_einj0[];
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index 910f018d92c..21a73a105d0 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -221,7 +221,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state);
* dsinit
*/
acpi_status
-acpi_ds_initialize_objects(acpi_native_uint table_index,
+acpi_ds_initialize_objects(u32 table_index,
struct acpi_namespace_node *start_node);
/*
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 1f591171bf3..e5a890ffeb0 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -108,8 +108,9 @@
#define AE_BAD_HEX_CONSTANT (acpi_status) (0x0007 | AE_CODE_PROGRAMMER)
#define AE_BAD_OCTAL_CONSTANT (acpi_status) (0x0008 | AE_CODE_PROGRAMMER)
#define AE_BAD_DECIMAL_CONSTANT (acpi_status) (0x0009 | AE_CODE_PROGRAMMER)
+#define AE_MISSING_ARGUMENTS (acpi_status) (0x000A | AE_CODE_PROGRAMMER)
-#define AE_CODE_PGM_MAX 0x0009
+#define AE_CODE_PGM_MAX 0x000A
/*
* Acpi table exceptions
@@ -225,6 +226,7 @@ char const *acpi_gbl_exception_names_env[] = {
};
char const *acpi_gbl_exception_names_pgm[] = {
+ NULL,
"AE_BAD_PARAMETER",
"AE_BAD_CHARACTER",
"AE_BAD_PATHNAME",
@@ -233,10 +235,12 @@ char const *acpi_gbl_exception_names_pgm[] = {
"AE_ALIGNMENT",
"AE_BAD_HEX_CONSTANT",
"AE_BAD_OCTAL_CONSTANT",
- "AE_BAD_DECIMAL_CONSTANT"
+ "AE_BAD_DECIMAL_CONSTANT",
+ "AE_MISSING_ARGUMENTS"
};
char const *acpi_gbl_exception_names_tbl[] = {
+ NULL,
"AE_BAD_SIGNATURE",
"AE_BAD_HEADER",
"AE_BAD_CHECKSUM",
@@ -246,6 +250,7 @@ char const *acpi_gbl_exception_names_tbl[] = {
};
char const *acpi_gbl_exception_names_aml[] = {
+ NULL,
"AE_AML_ERROR",
"AE_AML_PARSE",
"AE_AML_BAD_OPCODE",
@@ -283,6 +288,7 @@ char const *acpi_gbl_exception_names_aml[] = {
};
char const *acpi_gbl_exception_names_ctrl[] = {
+ NULL,
"AE_CTRL_RETURN_VALUE",
"AE_CTRL_PENDING",
"AE_CTRL_TERMINATE",
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 74ad971241d..15dda46b70d 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -140,7 +140,7 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags;
*/
ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
-extern acpi_native_uint acpi_gbl_permanent_mmap;
+extern u8 acpi_gbl_permanent_mmap;
/* These addresses are calculated from FADT address values */
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index d4fb9bbc903..97a72b19327 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -87,6 +87,8 @@ acpi_status acpi_hw_clear_acpi_status(void);
/*
* hwgpe - GPE support
*/
+acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
acpi_status
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);
@@ -100,11 +102,9 @@ acpi_status
acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block);
-#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
acpi_event_status * event_status);
-#endif /* ACPI_FUTURE_USAGE */
acpi_status acpi_hw_disable_all_gpes(void);
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index e249ce5d330..e8db7a3143a 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -366,10 +366,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth);
void
acpi_ex_dump_operands(union acpi_operand_object **operands,
- acpi_interpreter_mode interpreter_mode,
- char *ident,
- u32 num_levels,
- char *note, char *module_name, u32 line_number);
+ const char *opcode_name, u32 num_opcodes);
#ifdef ACPI_FUTURE_USAGE
void
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index c5cdc32ac2f..b221c8583dd 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -98,8 +98,8 @@ union acpi_parse_object;
static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
"ACPI_MTX_Interpreter",
- "ACPI_MTX_Tables",
"ACPI_MTX_Namespace",
+ "ACPI_MTX_Tables",
"ACPI_MTX_Events",
"ACPI_MTX_Caches",
"ACPI_MTX_Memory",
@@ -282,8 +282,8 @@ struct acpi_predefined_names {
/* Info structure used to convert external<->internal namestrings */
struct acpi_namestring_info {
- char *external_name;
- char *next_external_char;
+ const char *external_name;
+ const char *next_external_char;
char *internal_name;
u32 length;
u32 num_segments;
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index fb41a3b802f..57ab9e9d759 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -80,12 +80,12 @@
*/
#define ACPI_CAST_PTR(t, p) ((t *) (acpi_uintptr_t) (p))
#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **) (acpi_uintptr_t) (p))
-#define ACPI_ADD_PTR(t,a,b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8,(a)) + (acpi_native_uint)(b)))
-#define ACPI_PTR_DIFF(a,b) (acpi_native_uint) (ACPI_CAST_PTR (u8,(a)) - ACPI_CAST_PTR (u8,(b)))
+#define ACPI_ADD_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8,(a)) + (acpi_size)(b)))
+#define ACPI_PTR_DIFF(a, b) (acpi_size) (ACPI_CAST_PTR (u8,(a)) - ACPI_CAST_PTR (u8,(b)))
/* Pointer/Integer type conversions */
-#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i)
+#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void, (void *) NULL, (acpi_size) i)
#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p,(void *) NULL)
#define ACPI_OFFSET(d,f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL)
#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i)
@@ -296,22 +296,22 @@ struct acpi_integer_overlay {
/*
* Rounding macros (Power of two boundaries only)
*/
-#define ACPI_ROUND_DOWN(value,boundary) (((acpi_native_uint)(value)) & \
- (~(((acpi_native_uint) boundary)-1)))
+#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \
+ (~(((acpi_size) boundary)-1)))
-#define ACPI_ROUND_UP(value,boundary) ((((acpi_native_uint)(value)) + \
- (((acpi_native_uint) boundary)-1)) & \
- (~(((acpi_native_uint) boundary)-1)))
+#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \
+ (((acpi_size) boundary)-1)) & \
+ (~(((acpi_size) boundary)-1)))
-/* Note: sizeof(acpi_native_uint) evaluates to either 2, 4, or 8 */
+/* Note: sizeof(acpi_size) evaluates to either 4 or 8 (32- vs 64-bit mode) */
#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a,4)
#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a,8)
-#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,sizeof(acpi_native_uint))
+#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,sizeof(acpi_size))
#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a,4)
#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a,8)
-#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,sizeof(acpi_native_uint))
+#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,sizeof(acpi_size))
#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7)
#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a))
@@ -322,7 +322,7 @@ struct acpi_integer_overlay {
#define ACPI_ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary))
-#define ACPI_IS_MISALIGNED(value) (((acpi_native_uint)value) & (sizeof(acpi_native_uint)-1))
+#define ACPI_IS_MISALIGNED(value) (((acpi_size)value) & (sizeof(acpi_size)-1))
/*
* Bitmask creation
@@ -414,7 +414,7 @@ struct acpi_integer_overlay {
* error messages. The __FILE__ macro is not very useful for this, because it
* often includes the entire pathname to the module
*/
-#define ACPI_MODULE_NAME(name) static char ACPI_UNUSED_VAR *_acpi_module_name = name;
+#define ACPI_MODULE_NAME(name) static const char ACPI_UNUSED_VAR _acpi_module_name[] = name;
#else
#define ACPI_MODULE_NAME(name)
#endif
@@ -467,19 +467,17 @@ struct acpi_integer_overlay {
/*
* If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header,
* define it now. This is the case where there the compiler does not support
- * a __FUNCTION__ macro or equivalent. We save the function name on the
- * local stack.
+ * a __FUNCTION__ macro or equivalent.
*/
#ifndef ACPI_GET_FUNCTION_NAME
#define ACPI_GET_FUNCTION_NAME _acpi_function_name
/*
* The Name parameter should be the procedure name as a quoted string.
- * This is declared as a local string ("MyFunctionName") so that it can
- * be also used by the function exit macros below.
+ * The function name is also used by the function exit macros below.
* Note: (const char) is used to be compatible with the debug interfaces
* and macros such as __FUNCTION__.
*/
-#define ACPI_FUNCTION_NAME(name) const char *_acpi_function_name = #name;
+#define ACPI_FUNCTION_NAME(name) static const char _acpi_function_name[] = #name;
#else
/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */
@@ -599,7 +597,7 @@ struct acpi_integer_overlay {
/* Stack and buffer dumping */
#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a),0)
-#define ACPI_DUMP_OPERANDS(a,b,c,d,e) acpi_ex_dump_operands(a,b,c,d,e,_acpi_module_name,__LINE__)
+#define ACPI_DUMP_OPERANDS(a,b,c) acpi_ex_dump_operands(a,b,c)
#define ACPI_DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b)
#define ACPI_DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d)
@@ -635,7 +633,7 @@ struct acpi_integer_overlay {
#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0)
#define ACPI_FUNCTION_ENTRY() do { } while(0)
#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0)
-#define ACPI_DUMP_OPERANDS(a,b,c,d,e) do { } while(0)
+#define ACPI_DUMP_OPERANDS(a,b,c) do { } while(0)
#define ACPI_DUMP_ENTRY(a,b) do { } while(0)
#define ACPI_DUMP_TABLES(a,b) do { } while(0)
#define ACPI_DUMP_PATHNAME(a,b,c,d) do { } while(0)
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 713b30903fe..9ed70a05058 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -86,8 +86,7 @@ acpi_status acpi_ns_initialize_devices(void);
acpi_status acpi_ns_load_namespace(void);
acpi_status
-acpi_ns_load_table(acpi_native_uint table_index,
- struct acpi_namespace_node *node);
+acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node);
/*
* nswalk - walk the namespace
@@ -108,12 +107,11 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct
* nsparse - table parsing
*/
acpi_status
-acpi_ns_parse_table(acpi_native_uint table_index,
- struct acpi_namespace_node *start_node);
+acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node);
acpi_status
-acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index,
+acpi_ns_one_complete_parse(u32 pass_number,
+ u32 table_index,
struct acpi_namespace_node *start_node);
/*
@@ -201,7 +199,7 @@ acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for);
acpi_status
acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
- char *external_pathname,
+ const char *external_pathname,
u32 flags, struct acpi_namespace_node **out_node);
acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node);
@@ -265,28 +263,30 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node);
u32 acpi_ns_local(acpi_object_type type);
void
-acpi_ns_report_error(char *module_name,
+acpi_ns_report_error(const char *module_name,
u32 line_number,
- char *internal_name, acpi_status lookup_status);
+ const char *internal_name, acpi_status lookup_status);
void
-acpi_ns_report_method_error(char *module_name,
+acpi_ns_report_method_error(const char *module_name,
u32 line_number,
- char *message,
+ const char *message,
struct acpi_namespace_node *node,
- char *path, acpi_status lookup_status);
+ const char *path, acpi_status lookup_status);
-void acpi_ns_print_node_pathname(struct acpi_namespace_node *node, char *msg);
+void
+acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg);
acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info);
void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info);
-acpi_status acpi_ns_internalize_name(char *dotted_name, char **converted_name);
+acpi_status
+acpi_ns_internalize_name(const char *dotted_name, char **converted_name);
acpi_status
acpi_ns_externalize_name(u32 internal_name_length,
- char *internal_name,
+ const char *internal_name,
u32 * converted_name_length, char **converted_name);
struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 2f1c68c7a72..db90a74f871 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -376,9 +376,9 @@ acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
#ifdef CONFIG_PM_SLEEP
-int acpi_pm_device_sleep_state(struct device *, int, int *);
+int acpi_pm_device_sleep_state(struct device *, int *);
#else /* !CONFIG_PM_SLEEP */
-static inline int acpi_pm_device_sleep_state(struct device *d, int w, int *p)
+static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
{
if (p)
*p = ACPI_STATE_D0;
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index d4a560d2deb..3f93a6b4e17 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -144,7 +144,7 @@ void acpi_os_release_mutex(acpi_mutex handle);
void *acpi_os_allocate(acpi_size size);
void __iomem *acpi_os_map_memory(acpi_physical_address where,
- acpi_native_uint length);
+ acpi_size length);
void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size);
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 2c3806e6546..94d94e126e9 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -98,7 +98,7 @@ void acpi_free(void *address);
*/
acpi_status acpi_reallocate_root_table(void);
-acpi_status acpi_find_root_pointer(acpi_native_uint * rsdp_address);
+acpi_status acpi_find_root_pointer(acpi_size *rsdp_address);
acpi_status acpi_load_tables(void);
@@ -108,15 +108,15 @@ acpi_status acpi_unload_table_id(acpi_owner_id id);
acpi_status
acpi_get_table_header(acpi_string signature,
- acpi_native_uint instance,
+ u32 instance,
struct acpi_table_header *out_table_header);
acpi_status
acpi_get_table(acpi_string signature,
- acpi_native_uint instance, struct acpi_table_header **out_table);
+ u32 instance, struct acpi_table_header **out_table);
acpi_status
-acpi_get_table_by_index(acpi_native_uint table_index,
+acpi_get_table_by_index(u32 table_index,
struct acpi_table_header **out_table);
acpi_status
@@ -248,9 +248,7 @@ acpi_status acpi_disable_event(u32 event, u32 flags);
acpi_status acpi_clear_event(u32 event);
-#ifdef ACPI_FUTURE_USAGE
acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status);
-#endif /* ACPI_FUTURE_USAGE */
acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type);
@@ -260,12 +258,10 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags);
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags);
-#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_get_gpe_status(acpi_handle gpe_device,
u32 gpe_number,
u32 flags, acpi_event_status * event_status);
-#endif /* ACPI_FUTURE_USAGE */
acpi_status
acpi_install_gpe_block(acpi_handle gpe_device,
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index a907c67d651..7980a26bad3 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -108,7 +108,6 @@ struct acpi_walk_state {
union acpi_operand_object **caller_return_desc;
union acpi_generic_state *control_state; /* List of control states (nested IFs) */
struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */
- struct acpi_gpe_event_info *gpe_event_info; /* Info for GPE (_Lxx/_Exx methods only */
union acpi_operand_object *implicit_return_obj;
struct acpi_namespace_node *method_call_node; /* Called method Node */
union acpi_parse_object *method_call_op; /* method_call Op if running a method */
@@ -143,7 +142,7 @@ struct acpi_init_walk_info {
u16 package_init;
u16 object_count;
acpi_owner_id owner_id;
- acpi_native_uint table_index;
+ u32 table_index;
};
struct acpi_get_devices_info {
@@ -189,17 +188,12 @@ struct acpi_evaluate_info {
union acpi_operand_object **parameters;
struct acpi_namespace_node *resolved_node;
union acpi_operand_object *return_object;
+ u8 param_count;
u8 pass_number;
- u8 parameter_type;
u8 return_object_type;
u8 flags;
};
-/* Types for parameter_type above */
-
-#define ACPI_PARAM_ARGS 0
-#define ACPI_PARAM_GPE 1
-
/* Values for Flags above */
#define ACPI_IGNORE_RETURN_VALUE 1
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index 4b36a55b0b3..0cbe1b9ab52 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -49,7 +49,7 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count);
/*
* tbfadt - FADT parse/convert/validate
*/
-void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags);
+void acpi_tb_parse_fadt(u32 table_index, u8 flags);
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length);
@@ -58,8 +58,7 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length);
*/
acpi_status
acpi_tb_find_table(char *signature,
- char *oem_id,
- char *oem_table_id, acpi_native_uint * table_index);
+ char *oem_id, char *oem_table_id, u32 *table_index);
/*
* tbinstal - Table removal and deletion
@@ -69,30 +68,28 @@ acpi_status acpi_tb_resize_root_table_list(void);
acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
acpi_status
-acpi_tb_add_table(struct acpi_table_desc *table_desc,
- acpi_native_uint * table_index);
+acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index);
acpi_status
acpi_tb_store_table(acpi_physical_address address,
struct acpi_table_header *table,
- u32 length, u8 flags, acpi_native_uint * table_index);
+ u32 length, u8 flags, u32 *table_index);
void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
void acpi_tb_terminate(void);
-void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index);
+void acpi_tb_delete_namespace_by_owner(u32 table_index);
-acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index);
+acpi_status acpi_tb_allocate_owner_id(u32 table_index);
-acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index);
+acpi_status acpi_tb_release_owner_id(u32 table_index);
-acpi_status
-acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id);
+acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id);
-u8 acpi_tb_is_table_loaded(acpi_native_uint table_index);
+u8 acpi_tb_is_table_loaded(u32 table_index);
-void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded);
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
/*
* tbutils - table manager utilities
@@ -103,14 +100,14 @@ void
acpi_tb_print_table_header(acpi_physical_address address,
struct acpi_table_header *header);
-u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length);
+u8 acpi_tb_checksum(u8 *buffer, u32 length);
acpi_status
acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
void
acpi_tb_install_table(acpi_physical_address address,
- u8 flags, char *signature, acpi_native_uint table_index);
+ u8 flags, char *signature, u32 table_index);
acpi_status
acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags);
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 9af239bd115..d38f9be2f6e 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -300,6 +300,7 @@ struct acpi_table_dbgp {
/*******************************************************************************
*
* DMAR - DMA Remapping table
+ * From "Intel Virtualization Technology for Directed I/O", Sept. 2007
*
******************************************************************************/
@@ -310,6 +311,10 @@ struct acpi_table_dmar {
u8 reserved[10];
};
+/* Flags */
+
+#define ACPI_DMAR_INTR_REMAP (1)
+
/* DMAR subtable header */
struct acpi_dmar_header {
@@ -382,6 +387,20 @@ struct acpi_dmar_reserved_memory {
#define ACPI_DMAR_ALLOW_ALL (1)
+
+/* 2: Root Port ATS Capability Reporting Structure */
+
+struct acpi_dmar_atsr {
+ struct acpi_dmar_header header;
+ u8 flags;
+ u8 reserved;
+ u16 segment;
+};
+
+/* Flags */
+
+#define ACPI_DMAR_ALL_PORTS (1)
+
/*******************************************************************************
*
* ECDT - Embedded Controller Boot Resources Table
@@ -1156,9 +1175,9 @@ struct acpi_srat_mem_affinity {
u16 reserved; /* Reserved, must be zero */
u64 base_address;
u64 length;
- u32 memory_type; /* See acpi_address_range_id */
+ u32 reserved1;
u32 flags;
- u64 reserved1; /* Reserved, must be zero */
+ u64 reserved2; /* Reserved, must be zero */
};
/* Flags */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index dfea2d44048..4ea4f40bf89 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -110,10 +110,10 @@
* usually used for memory allocation, efficient loop counters, and array
* indexes. The types are similar to the size_t type in the C library and are
* required because there is no C type that consistently represents the native
- * data width.
+ * data width. ACPI_SIZE is needed because there is no guarantee that a
+ * kernel-level C library is present.
*
* ACPI_SIZE 16/32/64-bit unsigned value
- * ACPI_NATIVE_UINT 16/32/64-bit unsigned value
* ACPI_NATIVE_INT 16/32/64-bit signed value
*
*/
@@ -147,9 +147,9 @@ typedef int INT32;
/*! [End] no source code translation !*/
-typedef u64 acpi_native_uint;
typedef s64 acpi_native_int;
+typedef u64 acpi_size;
typedef u64 acpi_io_address;
typedef u64 acpi_physical_address;
@@ -186,9 +186,9 @@ typedef int INT32;
/*! [End] no source code translation !*/
-typedef u32 acpi_native_uint;
typedef s32 acpi_native_int;
+typedef u32 acpi_size;
typedef u32 acpi_io_address;
typedef u32 acpi_physical_address;
@@ -202,10 +202,6 @@ typedef u32 acpi_physical_address;
#error unknown ACPI_MACHINE_WIDTH
#endif
-/* Variable-width type, used instead of clib size_t */
-
-typedef acpi_native_uint acpi_size;
-
/*******************************************************************************
*
* OS-dependent and compiler-dependent types
@@ -219,7 +215,7 @@ typedef acpi_native_uint acpi_size;
/* Value returned by acpi_os_get_thread_id */
#ifndef acpi_thread_id
-#define acpi_thread_id acpi_native_uint
+#define acpi_thread_id acpi_size
#endif
/* Object returned from acpi_os_create_lock */
@@ -231,7 +227,7 @@ typedef acpi_native_uint acpi_size;
/* Flags for acpi_os_acquire_lock/acpi_os_release_lock */
#ifndef acpi_cpu_flags
-#define acpi_cpu_flags acpi_native_uint
+#define acpi_cpu_flags acpi_size
#endif
/* Object returned from acpi_os_create_cache */
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index b42cadf0730..69f8888771f 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -172,7 +172,7 @@ char *acpi_ut_strstr(char *string1, char *string2);
void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count);
-void *acpi_ut_memset(void *dest, acpi_native_uint value, acpi_size count);
+void *acpi_ut_memset(void *dest, u8 value, acpi_size count);
int acpi_ut_to_upper(int c);
@@ -245,41 +245,45 @@ void acpi_ut_track_stack_ptr(void);
void
acpi_ut_trace(u32 line_number,
- const char *function_name, char *module_name, u32 component_id);
+ const char *function_name,
+ const char *module_name, u32 component_id);
void
acpi_ut_trace_ptr(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, void *pointer);
+ const char *module_name, u32 component_id, void *pointer);
void
acpi_ut_trace_u32(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, u32 integer);
+ const char *module_name, u32 component_id, u32 integer);
void
acpi_ut_trace_str(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, char *string);
+ const char *module_name, u32 component_id, char *string);
void
acpi_ut_exit(u32 line_number,
- const char *function_name, char *module_name, u32 component_id);
+ const char *function_name,
+ const char *module_name, u32 component_id);
void
acpi_ut_status_exit(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, acpi_status status);
+ const char *module_name,
+ u32 component_id, acpi_status status);
void
acpi_ut_value_exit(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, acpi_integer value);
+ const char *module_name,
+ u32 component_id, acpi_integer value);
void
acpi_ut_ptr_exit(u32 line_number,
const char *function_name,
- char *module_name, u32 component_id, u8 * ptr);
+ const char *module_name, u32 component_id, u8 *ptr);
void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id);
@@ -297,33 +301,35 @@ void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print(u32 requested_debug_level,
u32 line_number,
const char *function_name,
- char *module_name,
- u32 component_id, char *format, ...) ACPI_PRINTF_LIKE(6);
+ const char *module_name,
+ u32 component_id,
+ const char *format, ...) ACPI_PRINTF_LIKE(6);
void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print_raw(u32 requested_debug_level,
u32 line_number,
const char *function_name,
- char *module_name,
+ const char *module_name,
u32 component_id,
- char *format, ...) ACPI_PRINTF_LIKE(6);
+ const char *format, ...) ACPI_PRINTF_LIKE(6);
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_error(char *module_name,
- u32 line_number, char *format, ...) ACPI_PRINTF_LIKE(3);
+acpi_ut_error(const char *module_name,
+ u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3);
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_exception(char *module_name,
+acpi_ut_exception(const char *module_name,
u32 line_number,
- acpi_status status, char *format, ...) ACPI_PRINTF_LIKE(4);
+ acpi_status status,
+ const char *format, ...) ACPI_PRINTF_LIKE(4);
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_warning(char *module_name,
- u32 line_number, char *format, ...) ACPI_PRINTF_LIKE(3);
+acpi_ut_warning(const char *module_name,
+ u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3);
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_info(char *module_name,
- u32 line_number, char *format, ...) ACPI_PRINTF_LIKE(3);
+acpi_ut_info(const char *module_name,
+ u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3);
/*
* utdelete - Object deletion and reference counts
@@ -376,13 +382,14 @@ acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest);
/*
* utobject - internal object create/delete/cache routines
*/
-union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name,
+union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char
+ *module_name,
u32 line_number,
u32 component_id,
acpi_object_type
type);
-void *acpi_ut_allocate_object_desc_dbg(char *module_name,
+void *acpi_ut_allocate_object_desc_dbg(const char *module_name,
u32 line_number, u32 component_id);
#define acpi_ut_create_internal_object(t) acpi_ut_create_internal_object_dbg (_acpi_module_name,__LINE__,_COMPONENT,t)
@@ -476,7 +483,7 @@ u8 acpi_ut_valid_acpi_name(u32 name);
acpi_name acpi_ut_repair_name(char *name);
-u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position);
+u8 acpi_ut_valid_acpi_char(char character, u32 position);
acpi_status
acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
@@ -543,26 +550,29 @@ acpi_status
acpi_ut_initialize_buffer(struct acpi_buffer *buffer,
acpi_size required_length);
-void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line);
+void *acpi_ut_allocate(acpi_size size,
+ u32 component, const char *module, u32 line);
void *acpi_ut_allocate_zeroed(acpi_size size,
- u32 component, char *module, u32 line);
+ u32 component, const char *module, u32 line);
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
void *acpi_ut_allocate_and_track(acpi_size size,
- u32 component, char *module, u32 line);
+ u32 component, const char *module, u32 line);
void *acpi_ut_allocate_zeroed_and_track(acpi_size size,
- u32 component, char *module, u32 line);
+ u32 component,
+ const char *module, u32 line);
void
-acpi_ut_free_and_track(void *address, u32 component, char *module, u32 line);
+acpi_ut_free_and_track(void *address,
+ u32 component, const char *module, u32 line);
#ifdef ACPI_FUTURE_USAGE
void acpi_ut_dump_allocation_info(void);
#endif /* ACPI_FUTURE_USAGE */
-void acpi_ut_dump_allocations(u32 component, char *module);
+void acpi_ut_dump_allocations(u32 component, const char *module);
acpi_status
acpi_ut_create_list(char *list_name,
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 06ebb6ef72a..3795590e152 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -255,7 +255,7 @@ extern void acpi_processor_unregister_performance(struct
int acpi_processor_notify_smm(struct module *calling_module);
/* for communication between multiple parts of the processor kernel module */
-extern struct acpi_processor *processors[NR_CPUS];
+DECLARE_PER_CPU(struct acpi_processor *, processors);
extern struct acpi_processor_errata errata;
void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
diff --git a/include/acpi/reboot.h b/include/acpi/reboot.h
index 8857f57e0b7..0419184ce88 100644
--- a/include/acpi/reboot.h
+++ b/include/acpi/reboot.h
@@ -1,9 +1,11 @@
+#ifndef __ACPI_REBOOT_H
+#define __ACPI_REBOOT_H
+
+#ifdef CONFIG_ACPI
+extern void acpi_reboot(void);
+#else
+static inline void acpi_reboot(void) { }
+#endif
-/*
- * Dummy placeholder to make the EFI patches apply to the x86 tree.
- * Andrew/Len, please just kill this file if you encounter it.
- */
-#ifndef acpi_reboot
-# define acpi_reboot() do { } while (0)
#endif
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 6aff126fc07..f88fa054d01 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -763,6 +763,8 @@ prefetchw (const void *x)
#define spin_lock_prefetch(x) prefetchw(x)
extern unsigned long boot_option_idle_override;
+extern unsigned long idle_halt;
+extern unsigned long idle_nomwait;
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index 7f738270459..55402d2ab93 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -727,6 +727,8 @@ extern int force_mwait;
extern void select_idle_routine(const struct cpuinfo_x86 *c);
extern unsigned long boot_option_idle_override;
+extern unsigned long idle_halt;
+extern unsigned long idle_nomwait;
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 32a441b05fd..88d68081a0f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -985,6 +985,9 @@ static inline int bdev_integrity_enabled(struct block_device *bdev, int rw)
static inline int blk_integrity_rq(struct request *rq)
{
+ if (rq->bio == NULL)
+ return 0;
+
return bio_integrity(rq->bio);
}
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 08934995c7a..deddeedf325 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -128,6 +128,15 @@ static inline void set_freezable(void)
}
/*
+ * Tell the freezer that the current task should be frozen by it and that it
+ * should send a fake signal to the task to freeze it.
+ */
+static inline void set_freezable_with_signal(void)
+{
+ current->flags &= ~(PF_NOFREEZE | PF_FREEZER_NOSIG);
+}
+
+/*
* Freezer-friendly wrappers around wait_event_interruptible() and
* wait_event_interruptible_timeout(), originally defined in <linux/wait.h>
*/
@@ -174,6 +183,7 @@ static inline void freezer_do_not_count(void) {}
static inline void freezer_count(void) {}
static inline int freezer_should_skip(struct task_struct *p) { return 0; }
static inline void set_freezable(void) {}
+static inline void set_freezable_with_signal(void) {}
#define wait_event_freezable(wq, condition) \
wait_event_interruptible(wq, condition)
diff --git a/include/linux/inet.h b/include/linux/inet.h
index 1354080cf8c..4cca05c9678 100644
--- a/include/linux/inet.h
+++ b/include/linux/inet.h
@@ -44,6 +44,13 @@
#include <linux/types.h>
+/*
+ * These mimic similar macros defined in user-space for inet_ntop(3).
+ * See /usr/include/netinet/in.h .
+ */
+#define INET_ADDRSTRLEN (16)
+#define INET6_ADDRSTRLEN (48)
+
extern __be32 in_aton(const char *str);
extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);
extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index c6801bffe76..2cd07cc2968 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -59,6 +59,7 @@ struct resource_list {
#define IORESOURCE_IRQ_HIGHLEVEL (1<<2)
#define IORESOURCE_IRQ_LOWLEVEL (1<<3)
#define IORESOURCE_IRQ_SHAREABLE (1<<4)
+#define IORESOURCE_IRQ_OPTIONAL (1<<5)
/* PnP DMA specific bits (IORESOURCE_BITS) */
#define IORESOURCE_DMA_TYPE_MASK (3<<0)
@@ -88,6 +89,10 @@ struct resource_list {
#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */
#define IORESOURCE_MEM_EXPANSIONROM (1<<6)
+/* PnP I/O specific bits (IORESOURCE_BITS) */
+#define IORESOURCE_IO_16BIT_ADDR (1<<0)
+#define IORESOURCE_IO_FIXED (1<<1)
+
/* PCI ROM control bits (IORESOURCE_BITS) */
#define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
#define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 27d6a8d98ce..29d26191873 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -12,9 +12,19 @@
#include <linux/magic.h>
/* Default timeout values */
+#define NFS_DEF_UDP_TIMEO (11)
+#define NFS_DEF_UDP_RETRANS (3)
+#define NFS_DEF_TCP_TIMEO (600)
+#define NFS_DEF_TCP_RETRANS (2)
+
#define NFS_MAX_UDP_TIMEOUT (60*HZ)
#define NFS_MAX_TCP_TIMEOUT (600*HZ)
+#define NFS_DEF_ACREGMIN (3)
+#define NFS_DEF_ACREGMAX (60)
+#define NFS_DEF_ACDIRMIN (30)
+#define NFS_DEF_ACDIRMAX (60)
+
/*
* When flushing a cluster of dirty pages, there can be different
* strategies:
diff --git a/include/linux/nfs_iostat.h b/include/linux/nfs_iostat.h
new file mode 100644
index 00000000000..1cb9a3fed2b
--- /dev/null
+++ b/include/linux/nfs_iostat.h
@@ -0,0 +1,119 @@
+/*
+ * User-space visible declarations for NFS client per-mount
+ * point statistics
+ *
+ * Copyright (C) 2005, 2006 Chuck Lever <cel@netapp.com>
+ *
+ * NFS client per-mount statistics provide information about the
+ * health of the NFS client and the health of each NFS mount point.
+ * Generally these are not for detailed problem diagnosis, but
+ * simply to indicate that there is a problem.
+ *
+ * These counters are not meant to be human-readable, but are meant
+ * to be integrated into system monitoring tools such as "sar" and
+ * "iostat". As such, the counters are sampled by the tools over
+ * time, and are never zeroed after a file system is mounted.
+ * Moving averages can be computed by the tools by taking the
+ * difference between two instantaneous samples and dividing that
+ * by the time between the samples.
+ */
+
+#ifndef _LINUX_NFS_IOSTAT
+#define _LINUX_NFS_IOSTAT
+
+#define NFS_IOSTAT_VERS "1.0"
+
+/*
+ * NFS byte counters
+ *
+ * 1. SERVER - the number of payload bytes read from or written
+ * to the server by the NFS client via an NFS READ or WRITE
+ * request.
+ *
+ * 2. NORMAL - the number of bytes read or written by applications
+ * via the read(2) and write(2) system call interfaces.
+ *
+ * 3. DIRECT - the number of bytes read or written from files
+ * opened with the O_DIRECT flag.
+ *
+ * These counters give a view of the data throughput into and out
+ * of the NFS client. Comparing the number of bytes requested by
+ * an application with the number of bytes the client requests from
+ * the server can provide an indication of client efficiency
+ * (per-op, cache hits, etc).
+ *
+ * These counters can also help characterize which access methods
+ * are in use. DIRECT by itself shows whether there is any O_DIRECT
+ * traffic. NORMAL + DIRECT shows how much data is going through
+ * the system call interface. A large amount of SERVER traffic
+ * without much NORMAL or DIRECT traffic shows that applications
+ * are using mapped files.
+ *
+ * NFS page counters
+ *
+ * These count the number of pages read or written via nfs_readpage(),
+ * nfs_readpages(), or their write equivalents.
+ *
+ * NB: When adding new byte counters, please include the measured
+ * units in the name of each byte counter to help users of this
+ * interface determine what exactly is being counted.
+ */
+enum nfs_stat_bytecounters {
+ NFSIOS_NORMALREADBYTES = 0,
+ NFSIOS_NORMALWRITTENBYTES,
+ NFSIOS_DIRECTREADBYTES,
+ NFSIOS_DIRECTWRITTENBYTES,
+ NFSIOS_SERVERREADBYTES,
+ NFSIOS_SERVERWRITTENBYTES,
+ NFSIOS_READPAGES,
+ NFSIOS_WRITEPAGES,
+ __NFSIOS_BYTESMAX,
+};
+
+/*
+ * NFS event counters
+ *
+ * These counters provide a low-overhead way of monitoring client
+ * activity without enabling NFS trace debugging. The counters
+ * show the rate at which VFS requests are made, and how often the
+ * client invalidates its data and attribute caches. This allows
+ * system administrators to monitor such things as how close-to-open
+ * is working, and answer questions such as "why are there so many
+ * GETATTR requests on the wire?"
+ *
+ * They also count anamolous events such as short reads and writes,
+ * silly renames due to close-after-delete, and operations that
+ * change the size of a file (such operations can often be the
+ * source of data corruption if applications aren't using file
+ * locking properly).
+ */
+enum nfs_stat_eventcounters {
+ NFSIOS_INODEREVALIDATE = 0,
+ NFSIOS_DENTRYREVALIDATE,
+ NFSIOS_DATAINVALIDATE,
+ NFSIOS_ATTRINVALIDATE,
+ NFSIOS_VFSOPEN,
+ NFSIOS_VFSLOOKUP,
+ NFSIOS_VFSACCESS,
+ NFSIOS_VFSUPDATEPAGE,
+ NFSIOS_VFSREADPAGE,
+ NFSIOS_VFSREADPAGES,
+ NFSIOS_VFSWRITEPAGE,
+ NFSIOS_VFSWRITEPAGES,
+ NFSIOS_VFSGETDENTS,
+ NFSIOS_VFSSETATTR,
+ NFSIOS_VFSFLUSH,
+ NFSIOS_VFSFSYNC,
+ NFSIOS_VFSLOCK,
+ NFSIOS_VFSRELEASE,
+ NFSIOS_CONGESTIONWAIT,
+ NFSIOS_SETATTRTRUNC,
+ NFSIOS_EXTENDWRITE,
+ NFSIOS_SILLYRENAME,
+ NFSIOS_SHORTREAD,
+ NFSIOS_SHORTWRITE,
+ NFSIOS_DELAY,
+ __NFSIOS_COUNTSMAX,
+};
+
+#endif /* _LINUX_NFS_IOSTAT */
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index a1676e19e49..3c60685d972 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -27,9 +27,12 @@
/*
* Valid flags for a dirty buffer
*/
-#define PG_BUSY 0
-#define PG_NEED_COMMIT 1
-#define PG_NEED_RESCHED 2
+enum {
+ PG_BUSY = 0,
+ PG_CLEAN,
+ PG_NEED_COMMIT,
+ PG_NEED_RESCHED,
+};
struct nfs_inode;
struct nfs_page {
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 24263bb8e0b..8c77c11224d 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -829,9 +829,8 @@ struct nfs_rpc_ops {
int (*write_done) (struct rpc_task *, struct nfs_write_data *);
void (*commit_setup) (struct nfs_write_data *, struct rpc_message *);
int (*commit_done) (struct rpc_task *, struct nfs_write_data *);
- int (*file_open) (struct inode *, struct file *);
- int (*file_release) (struct inode *, struct file *);
int (*lock)(struct file *, int, struct file_lock *);
+ int (*lock_check_bounds)(const struct file_lock *);
void (*clear_acl_cache)(struct inode *);
};
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 63b128d512f..1ce54b63085 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -1,6 +1,8 @@
/*
* Linux Plug and Play Support
* Copyright by Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#ifndef _LINUX_PNP_H
@@ -15,7 +17,6 @@
struct pnp_protocol;
struct pnp_dev;
-struct pnp_resource_table;
/*
* Resource Management
@@ -24,7 +25,14 @@ struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int);
static inline int pnp_resource_valid(struct resource *res)
{
- if (res && !(res->flags & IORESOURCE_UNSET))
+ if (res)
+ return 1;
+ return 0;
+}
+
+static inline int pnp_resource_enabled(struct resource *res)
+{
+ if (res && !(res->flags & IORESOURCE_DISABLED))
return 1;
return 0;
}
@@ -40,19 +48,31 @@ static inline resource_size_t pnp_resource_len(struct resource *res)
static inline resource_size_t pnp_port_start(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_IO, bar)->start;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_IO, bar);
+
+ if (pnp_resource_valid(res))
+ return res->start;
+ return 0;
}
static inline resource_size_t pnp_port_end(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_IO, bar)->end;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_IO, bar);
+
+ if (pnp_resource_valid(res))
+ return res->end;
+ return 0;
}
static inline unsigned long pnp_port_flags(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_IO, bar)->flags;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_IO, bar);
+
+ if (pnp_resource_valid(res))
+ return res->flags;
+ return IORESOURCE_IO | IORESOURCE_AUTO;
}
static inline int pnp_port_valid(struct pnp_dev *dev, unsigned int bar)
@@ -63,25 +83,41 @@ static inline int pnp_port_valid(struct pnp_dev *dev, unsigned int bar)
static inline resource_size_t pnp_port_len(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_resource_len(pnp_get_resource(dev, IORESOURCE_IO, bar));
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_IO, bar);
+
+ if (pnp_resource_valid(res))
+ return pnp_resource_len(res);
+ return 0;
}
static inline resource_size_t pnp_mem_start(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_MEM, bar)->start;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_MEM, bar);
+
+ if (pnp_resource_valid(res))
+ return res->start;
+ return 0;
}
static inline resource_size_t pnp_mem_end(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_MEM, bar)->end;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_MEM, bar);
+
+ if (pnp_resource_valid(res))
+ return res->end;
+ return 0;
}
static inline unsigned long pnp_mem_flags(struct pnp_dev *dev, unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_MEM, bar)->flags;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_MEM, bar);
+
+ if (pnp_resource_valid(res))
+ return res->flags;
+ return IORESOURCE_MEM | IORESOURCE_AUTO;
}
static inline int pnp_mem_valid(struct pnp_dev *dev, unsigned int bar)
@@ -92,18 +128,30 @@ static inline int pnp_mem_valid(struct pnp_dev *dev, unsigned int bar)
static inline resource_size_t pnp_mem_len(struct pnp_dev *dev,
unsigned int bar)
{
- return pnp_resource_len(pnp_get_resource(dev, IORESOURCE_MEM, bar));
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_MEM, bar);
+
+ if (pnp_resource_valid(res))
+ return pnp_resource_len(res);
+ return 0;
}
static inline resource_size_t pnp_irq(struct pnp_dev *dev, unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_IRQ, bar)->start;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_IRQ, bar);
+
+ if (pnp_resource_valid(res))
+ return res->start;
+ return -1;
}
static inline unsigned long pnp_irq_flags(struct pnp_dev *dev, unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_IRQ, bar)->flags;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_IRQ, bar);
+
+ if (pnp_resource_valid(res))
+ return res->flags;
+ return IORESOURCE_IRQ | IORESOURCE_AUTO;
}
static inline int pnp_irq_valid(struct pnp_dev *dev, unsigned int bar)
@@ -114,12 +162,20 @@ static inline int pnp_irq_valid(struct pnp_dev *dev, unsigned int bar)
static inline resource_size_t pnp_dma(struct pnp_dev *dev, unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_DMA, bar)->start;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_DMA, bar);
+
+ if (pnp_resource_valid(res))
+ return res->start;
+ return -1;
}
static inline unsigned long pnp_dma_flags(struct pnp_dev *dev, unsigned int bar)
{
- return pnp_get_resource(dev, IORESOURCE_DMA, bar)->flags;
+ struct resource *res = pnp_get_resource(dev, IORESOURCE_DMA, bar);
+
+ if (pnp_resource_valid(res))
+ return res->flags;
+ return IORESOURCE_DMA | IORESOURCE_AUTO;
}
static inline int pnp_dma_valid(struct pnp_dev *dev, unsigned int bar)
@@ -128,57 +184,6 @@ static inline int pnp_dma_valid(struct pnp_dev *dev, unsigned int bar)
}
-#define PNP_PORT_FLAG_16BITADDR (1<<0)
-#define PNP_PORT_FLAG_FIXED (1<<1)
-
-struct pnp_port {
- unsigned short min; /* min base number */
- unsigned short max; /* max base number */
- unsigned char align; /* align boundary */
- unsigned char size; /* size of range */
- unsigned char flags; /* port flags */
- unsigned char pad; /* pad */
- struct pnp_port *next; /* next port */
-};
-
-#define PNP_IRQ_NR 256
-struct pnp_irq {
- DECLARE_BITMAP(map, PNP_IRQ_NR); /* bitmask for IRQ lines */
- unsigned char flags; /* IRQ flags */
- unsigned char pad; /* pad */
- struct pnp_irq *next; /* next IRQ */
-};
-
-struct pnp_dma {
- unsigned char map; /* bitmask for DMA channels */
- unsigned char flags; /* DMA flags */
- struct pnp_dma *next; /* next port */
-};
-
-struct pnp_mem {
- unsigned int min; /* min base number */
- unsigned int max; /* max base number */
- unsigned int align; /* align boundary */
- unsigned int size; /* size of range */
- unsigned char flags; /* memory flags */
- unsigned char pad; /* pad */
- struct pnp_mem *next; /* next memory resource */
-};
-
-#define PNP_RES_PRIORITY_PREFERRED 0
-#define PNP_RES_PRIORITY_ACCEPTABLE 1
-#define PNP_RES_PRIORITY_FUNCTIONAL 2
-#define PNP_RES_PRIORITY_INVALID 65535
-
-struct pnp_option {
- unsigned short priority; /* priority */
- struct pnp_port *port; /* first port */
- struct pnp_irq *irq; /* first IRQ */
- struct pnp_dma *dma; /* first DMA */
- struct pnp_mem *mem; /* first memory resource */
- struct pnp_option *next; /* used to chain dependent resources */
-};
-
/*
* Device Management
*/
@@ -246,9 +251,9 @@ struct pnp_dev {
int active;
int capabilities;
- struct pnp_option *independent;
- struct pnp_option *dependent;
- struct pnp_resource_table *res;
+ unsigned int num_dependent_sets;
+ struct list_head resources;
+ struct list_head options;
char name[PNP_NAME_LEN]; /* contains a human-readable name */
int flags; /* used by protocols */
@@ -425,6 +430,8 @@ void pnp_unregister_card_driver(struct pnp_card_driver *drv);
extern struct list_head pnp_cards;
/* resource management */
+int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t base,
+ resource_size_t size);
int pnp_auto_config_dev(struct pnp_dev *dev);
int pnp_start_dev(struct pnp_dev *dev);
int pnp_stop_dev(struct pnp_dev *dev);
@@ -452,6 +459,9 @@ static inline int pnp_register_card_driver(struct pnp_card_driver *drv) { return
static inline void pnp_unregister_card_driver(struct pnp_card_driver *drv) { }
/* resource management */
+static inline int pnp_possible_config(struct pnp_dev *dev, int type,
+ resource_size_t base,
+ resource_size_t size) { return 0; }
static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 21349173d14..ba2f859c6e4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1494,6 +1494,7 @@ static inline void put_task_struct(struct task_struct *t)
#define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */
#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezeable */
+#define PF_FREEZER_NOSIG 0x80000000 /* Freezer won't send signals to it */
/*
* Only the _current_ task can read/write to tsk->flags, but other
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 6fff7f82ef1..e5bfe01ee30 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -42,7 +42,8 @@ struct rpc_clnt {
unsigned int cl_softrtry : 1,/* soft timeouts */
cl_discrtry : 1,/* disconnect before retry */
- cl_autobind : 1;/* use getport() */
+ cl_autobind : 1,/* use getport() */
+ cl_chatty : 1;/* be verbose */
struct rpc_rtt * cl_rtt; /* RTO estimator data */
const struct rpc_timeout *cl_timeout; /* Timeout strategy */
@@ -114,6 +115,7 @@ struct rpc_create_args {
#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3)
#define RPC_CLNT_CREATE_NOPING (1UL << 4)
#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5)
+#define RPC_CLNT_CREATE_QUIET (1UL << 6)
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
@@ -123,6 +125,9 @@ void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
int rpcb_register(u32, u32, int, unsigned short, int *);
+int rpcb_v4_register(const u32 program, const u32 version,
+ const struct sockaddr *address,
+ const char *netid, int *result);
int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
void rpcb_getport_async(struct rpc_task *);
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index d1a5c8c1a0f..64981a2f1ca 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -135,7 +135,6 @@ struct rpc_task_setup {
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
-#define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL)
#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT)
#define RPC_TASK_RUNNING 0
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b11f06dc149..cfb1d43ab80 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -299,6 +299,7 @@ int __ref cpu_down(unsigned int cpu)
cpu_maps_update_done();
return err;
}
+EXPORT_SYMBOL(cpu_down);
#endif /*CONFIG_HOTPLUG_CPU*/
/* Requires cpu_add_remove_lock to be held */
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 97747cdd37c..ac3fb732664 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -235,7 +235,7 @@ int kthreadd(void *unused)
set_user_nice(tsk, KTHREAD_NICE_LEVEL);
set_cpus_allowed(tsk, CPU_MASK_ALL);
- current->flags |= PF_NOFREEZE;
+ current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/kernel/power/process.c b/kernel/power/process.c
index f1d0b345c9b..5fb87652f21 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -19,9 +19,6 @@
*/
#define TIMEOUT (20 * HZ)
-#define FREEZER_KERNEL_THREADS 0
-#define FREEZER_USER_SPACE 1
-
static inline int freezeable(struct task_struct * p)
{
if ((p == current) ||
@@ -84,63 +81,53 @@ static void fake_signal_wake_up(struct task_struct *p)
spin_unlock_irqrestore(&p->sighand->siglock, flags);
}
-static int has_mm(struct task_struct *p)
+static inline bool should_send_signal(struct task_struct *p)
{
- return (p->mm && !(p->flags & PF_BORROWED_MM));
+ return !(p->flags & PF_FREEZER_NOSIG);
}
/**
* freeze_task - send a freeze request to given task
* @p: task to send the request to
- * @with_mm_only: if set, the request will only be sent if the task has its
- * own mm
- * Return value: 0, if @with_mm_only is set and the task has no mm of its
- * own or the task is frozen, 1, otherwise
+ * @sig_only: if set, the request will only be sent if the task has the
+ * PF_FREEZER_NOSIG flag unset
+ * Return value: 'false', if @sig_only is set and the task has
+ * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
*
- * The freeze request is sent by seting the tasks's TIF_FREEZE flag and
+ * The freeze request is sent by setting the tasks's TIF_FREEZE flag and
* either sending a fake signal to it or waking it up, depending on whether
- * or not it has its own mm (ie. it is a user land task). If @with_mm_only
- * is set and the task has no mm of its own (ie. it is a kernel thread),
- * its TIF_FREEZE flag should not be set.
- *
- * The task_lock() is necessary to prevent races with exit_mm() or
- * use_mm()/unuse_mm() from occuring.
+ * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task
+ * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
+ * TIF_FREEZE flag will not be set.
*/
-static int freeze_task(struct task_struct *p, int with_mm_only)
+static bool freeze_task(struct task_struct *p, bool sig_only)
{
- int ret = 1;
+ /*
+ * We first check if the task is freezing and next if it has already
+ * been frozen to avoid the race with frozen_process() which first marks
+ * the task as frozen and next clears its TIF_FREEZE.
+ */
+ if (!freezing(p)) {
+ rmb();
+ if (frozen(p))
+ return false;
- task_lock(p);
- if (freezing(p)) {
- if (has_mm(p)) {
- if (!signal_pending(p))
- fake_signal_wake_up(p);
- } else {
- if (with_mm_only)
- ret = 0;
- else
- wake_up_state(p, TASK_INTERRUPTIBLE);
- }
+ if (!sig_only || should_send_signal(p))
+ set_freeze_flag(p);
+ else
+ return false;
+ }
+
+ if (should_send_signal(p)) {
+ if (!signal_pending(p))
+ fake_signal_wake_up(p);
+ } else if (sig_only) {
+ return false;
} else {
- rmb();
- if (frozen(p)) {
- ret = 0;
- } else {
- if (has_mm(p)) {
- set_freeze_flag(p);
- fake_signal_wake_up(p);
- } else {
- if (with_mm_only) {
- ret = 0;
- } else {
- set_freeze_flag(p);
- wake_up_state(p, TASK_INTERRUPTIBLE);
- }
- }
- }
+ wake_up_state(p, TASK_INTERRUPTIBLE);
}
- task_unlock(p);
- return ret;
+
+ return true;
}
static void cancel_freezing(struct task_struct *p)
@@ -156,7 +143,7 @@ static void cancel_freezing(struct task_struct *p)
}
}
-static int try_to_freeze_tasks(int freeze_user_space)
+static int try_to_freeze_tasks(bool sig_only)
{
struct task_struct *g, *p;
unsigned long end_time;
@@ -175,7 +162,7 @@ static int try_to_freeze_tasks(int freeze_user_space)
if (frozen(p) || !freezeable(p))
continue;
- if (!freeze_task(p, freeze_user_space))
+ if (!freeze_task(p, sig_only))
continue;
/*
@@ -235,13 +222,13 @@ int freeze_processes(void)
int error;
printk("Freezing user space processes ... ");
- error = try_to_freeze_tasks(FREEZER_USER_SPACE);
+ error = try_to_freeze_tasks(true);
if (error)
goto Exit;
printk("done.\n");
printk("Freezing remaining freezable tasks ... ");
- error = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
+ error = try_to_freeze_tasks(false);
if (error)
goto Exit;
printk("done.");
@@ -251,7 +238,7 @@ int freeze_processes(void)
return error;
}
-static void thaw_tasks(int thaw_user_space)
+static void thaw_tasks(bool nosig_only)
{
struct task_struct *g, *p;
@@ -260,7 +247,7 @@ static void thaw_tasks(int thaw_user_space)
if (!freezeable(p))
continue;
- if (!p->mm == thaw_user_space)
+ if (nosig_only && should_send_signal(p))
continue;
thaw_process(p);
@@ -271,8 +258,8 @@ static void thaw_tasks(int thaw_user_space)
void thaw_processes(void)
{
printk("Restarting tasks ... ");
- thaw_tasks(FREEZER_KERNEL_THREADS);
- thaw_tasks(FREEZER_USER_SPACE);
+ thaw_tasks(true);
+ thaw_tasks(false);
schedule();
printk("done.\n");
}
diff --git a/kernel/power/user.c b/kernel/power/user.c
index f5512cb3aa8..a6332a31326 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -23,6 +23,7 @@
#include <linux/console.h>
#include <linux/cpu.h>
#include <linux/freezer.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -69,16 +70,22 @@ static int snapshot_open(struct inode *inode, struct file *filp)
struct snapshot_data *data;
int error;
- if (!atomic_add_unless(&snapshot_device_available, -1, 0))
- return -EBUSY;
+ mutex_lock(&pm_mutex);
+
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+ error = -EBUSY;
+ goto Unlock;
+ }
if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
atomic_inc(&snapshot_device_available);
- return -ENOSYS;
+ error = -ENOSYS;
+ goto Unlock;
}
if(create_basic_memory_bitmaps()) {
atomic_inc(&snapshot_device_available);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto Unlock;
}
nonseekable_open(inode, filp);
data = &snapshot_state;
@@ -98,33 +105,36 @@ static int snapshot_open(struct inode *inode, struct file *filp)
if (error)
pm_notifier_call_chain(PM_POST_HIBERNATION);
}
- if (error) {
+ if (error)
atomic_inc(&snapshot_device_available);
- return error;
- }
data->frozen = 0;
data->ready = 0;
data->platform_support = 0;
- return 0;
+ Unlock:
+ mutex_unlock(&pm_mutex);
+
+ return error;
}
static int snapshot_release(struct inode *inode, struct file *filp)
{
struct snapshot_data *data;
+ mutex_lock(&pm_mutex);
+
swsusp_free();
free_basic_memory_bitmaps();
data = filp->private_data;
free_all_swap_pages(data->swap);
- if (data->frozen) {
- mutex_lock(&pm_mutex);
+ if (data->frozen)
thaw_processes();
- mutex_unlock(&pm_mutex);
- }
pm_notifier_call_chain(data->mode == O_WRONLY ?
PM_POST_HIBERNATION : PM_POST_RESTORE);
atomic_inc(&snapshot_device_available);
+
+ mutex_unlock(&pm_mutex);
+
return 0;
}
@@ -134,9 +144,13 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
struct snapshot_data *data;
ssize_t res;
+ mutex_lock(&pm_mutex);
+
data = filp->private_data;
- if (!data->ready)
- return -ENODATA;
+ if (!data->ready) {
+ res = -ENODATA;
+ goto Unlock;
+ }
res = snapshot_read_next(&data->handle, count);
if (res > 0) {
if (copy_to_user(buf, data_of(data->handle), res))
@@ -144,6 +158,10 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
else
*offp = data->handle.offset;
}
+
+ Unlock:
+ mutex_unlock(&pm_mutex);
+
return res;
}
@@ -153,6 +171,8 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
struct snapshot_data *data;
ssize_t res;
+ mutex_lock(&pm_mutex);
+
data = filp->private_data;
res = snapshot_write_next(&data->handle, count);
if (res > 0) {
@@ -161,11 +181,14 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
else
*offp = data->handle.offset;
}
+
+ mutex_unlock(&pm_mutex);
+
return res;
}
-static int snapshot_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long snapshot_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
int error = 0;
struct snapshot_data *data;
@@ -179,6 +202,9 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (!mutex_trylock(&pm_mutex))
+ return -EBUSY;
+
data = filp->private_data;
switch (cmd) {
@@ -186,7 +212,6 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
case SNAPSHOT_FREEZE:
if (data->frozen)
break;
- mutex_lock(&pm_mutex);
printk("Syncing filesystems ... ");
sys_sync();
printk("done.\n");
@@ -194,7 +219,6 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = freeze_processes();
if (error)
thaw_processes();
- mutex_unlock(&pm_mutex);
if (!error)
data->frozen = 1;
break;
@@ -202,9 +226,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
case SNAPSHOT_UNFREEZE:
if (!data->frozen || data->ready)
break;
- mutex_lock(&pm_mutex);
thaw_processes();
- mutex_unlock(&pm_mutex);
data->frozen = 0;
break;
@@ -307,16 +329,11 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -EPERM;
break;
}
- if (!mutex_trylock(&pm_mutex)) {
- error = -EBUSY;
- break;
- }
/*
* Tasks are frozen and the notifiers have been called with
* PM_HIBERNATION_PREPARE
*/
error = suspend_devices_and_enter(PM_SUSPEND_MEM);
- mutex_unlock(&pm_mutex);
break;
case SNAPSHOT_PLATFORM_SUPPORT:
@@ -390,6 +407,8 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
}
+ mutex_unlock(&pm_mutex);
+
return error;
}
@@ -399,7 +418,7 @@ static const struct file_operations snapshot_fops = {
.read = snapshot_read,
.write = snapshot_write,
.llseek = no_llseek,
- .ioctl = snapshot_ioctl,
+ .unlocked_ioctl = snapshot_ioctl,
};
static struct miscdevice snapshot_device = {
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index cc12d5f5d5d..834a83199bd 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -63,22 +63,11 @@ static const struct rpc_credops gss_nullops;
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
-#define NFS_NGROUPS 16
-
-#define GSS_CRED_SLACK 1024 /* XXX: unused */
+#define GSS_CRED_SLACK 1024
/* length of a krb5 verifier (48), plus data added before arguments when
* using integrity (two 4-byte integers): */
#define GSS_VERF_SLACK 100
-/* XXX this define must match the gssd define
-* as it is passed to gssd to signal the use of
-* machine creds should be part of the shared rpc interface */
-
-#define CA_RUN_AS_MACHINE 0x00000200
-
-/* dump the buffer in `emacs-hexl' style */
-#define isprint(c) ((c > 0x1f) && (c < 0x7f))
-
struct gss_auth {
struct kref kref;
struct rpc_auth rpc_auth;
@@ -146,7 +135,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
q = (const void *)((const char *)p + len);
if (unlikely(q > end || q < p))
return ERR_PTR(-EFAULT);
- dest->data = kmemdup(p, len, GFP_KERNEL);
+ dest->data = kmemdup(p, len, GFP_NOFS);
if (unlikely(dest->data == NULL))
return ERR_PTR(-ENOMEM);
dest->len = len;
@@ -171,7 +160,7 @@ gss_alloc_context(void)
{
struct gss_cl_ctx *ctx;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_NOFS);
if (ctx != NULL) {
ctx->gc_proc = RPC_GSS_PROC_DATA;
ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */
@@ -272,7 +261,7 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
return NULL;
}
-/* Try to add a upcall to the pipefs queue.
+/* Try to add an upcall to the pipefs queue.
* If an upcall owned by our uid already exists, then we return a reference
* to that upcall instead of adding the new upcall.
*/
@@ -341,7 +330,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
{
struct gss_upcall_msg *gss_msg;
- gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL);
+ gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
if (gss_msg != NULL) {
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
@@ -493,7 +482,6 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
const void *p, *end;
void *buf;
- struct rpc_clnt *clnt;
struct gss_upcall_msg *gss_msg;
struct inode *inode = filp->f_path.dentry->d_inode;
struct gss_cl_ctx *ctx;
@@ -503,11 +491,10 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (mlen > MSG_BUF_MAXSIZE)
goto out;
err = -ENOMEM;
- buf = kmalloc(mlen, GFP_KERNEL);
+ buf = kmalloc(mlen, GFP_NOFS);
if (!buf)
goto out;
- clnt = RPC_I(inode)->private;
err = -EFAULT;
if (copy_from_user(buf, src, mlen))
goto err;
@@ -806,7 +793,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
dprintk("RPC: gss_create_cred for uid %d, flavor %d\n",
acred->uid, auth->au_flavor);
- if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL)))
+ if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))
goto out_err;
rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 60c3dba545d..ef45eba2248 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -70,7 +70,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
q = (const void *)((const char *)p + len);
if (unlikely(q > end || q < p))
return ERR_PTR(-EFAULT);
- res->data = kmemdup(p, len, GFP_KERNEL);
+ res->data = kmemdup(p, len, GFP_NOFS);
if (unlikely(res->data == NULL))
return ERR_PTR(-ENOMEM);
res->len = len;
@@ -131,7 +131,7 @@ gss_import_sec_context_kerberos(const void *p,
struct krb5_ctx *ctx;
int tmp;
- if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS)))
goto out_err;
p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 5deb4b6e451..035e1dd6af1 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -76,7 +76,7 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
q = (const void *)((const char *)p + len);
if (unlikely(q > end || q < p))
return ERR_PTR(-EFAULT);
- res->data = kmemdup(p, len, GFP_KERNEL);
+ res->data = kmemdup(p, len, GFP_NOFS);
if (unlikely(res->data == NULL))
return ERR_PTR(-ENOMEM);
return q;
@@ -90,7 +90,7 @@ gss_import_sec_context_spkm3(const void *p, size_t len,
struct spkm3_ctx *ctx;
int version;
- if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS)))
goto out_err;
p = simple_get_bytes(p, end, &version, sizeof(version));
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
index 6cdd241ad26..3308157436d 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_token.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_token.c
@@ -90,7 +90,7 @@ asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
int
decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
{
- if (!(out->data = kzalloc(explen,GFP_KERNEL)))
+ if (!(out->data = kzalloc(explen,GFP_NOFS)))
return 0;
out->len = explen;
memcpy(out->data, in, enclen);
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 44920b90bdc..46b2647c5bd 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -66,7 +66,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
acred->uid, acred->gid);
- if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
+ if (!(cred = kmalloc(sizeof(*cred), GFP_NOFS)))
return ERR_PTR(-ENOMEM);
rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 8945307556e..76739e928d0 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/kallsyms.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
@@ -58,7 +59,6 @@ static void call_start(struct rpc_task *task);
static void call_reserve(struct rpc_task *task);
static void call_reserveresult(struct rpc_task *task);
static void call_allocate(struct rpc_task *task);
-static void call_encode(struct rpc_task *task);
static void call_decode(struct rpc_task *task);
static void call_bind(struct rpc_task *task);
static void call_bind_status(struct rpc_task *task);
@@ -70,9 +70,9 @@ static void call_refreshresult(struct rpc_task *task);
static void call_timeout(struct rpc_task *task);
static void call_connect(struct rpc_task *task);
static void call_connect_status(struct rpc_task *task);
-static __be32 * call_header(struct rpc_task *task);
-static __be32 * call_verify(struct rpc_task *task);
+static __be32 *rpc_encode_header(struct rpc_task *task);
+static __be32 *rpc_verify_header(struct rpc_task *task);
static int rpc_ping(struct rpc_clnt *clnt, int flags);
static void rpc_register_client(struct rpc_clnt *clnt)
@@ -324,6 +324,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
clnt->cl_autobind = 1;
if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
clnt->cl_discrtry = 1;
+ if (!(args->flags & RPC_CLNT_CREATE_QUIET))
+ clnt->cl_chatty = 1;
return clnt;
}
@@ -690,6 +692,21 @@ rpc_restart_call(struct rpc_task *task)
}
EXPORT_SYMBOL_GPL(rpc_restart_call);
+#ifdef RPC_DEBUG
+static const char *rpc_proc_name(const struct rpc_task *task)
+{
+ const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
+
+ if (proc) {
+ if (proc->p_name)
+ return proc->p_name;
+ else
+ return "NULL";
+ } else
+ return "no proc";
+}
+#endif
+
/*
* 0. Initial state
*
@@ -701,9 +718,9 @@ call_start(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
- dprintk("RPC: %5u call_start %s%d proc %d (%s)\n", task->tk_pid,
+ dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid,
clnt->cl_protname, clnt->cl_vers,
- task->tk_msg.rpc_proc->p_proc,
+ rpc_proc_name(task),
(RPC_IS_ASYNC(task) ? "async" : "sync"));
/* Increment call count */
@@ -861,7 +878,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
* 3. Encode arguments of an RPC call
*/
static void
-call_encode(struct rpc_task *task)
+rpc_xdr_encode(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
kxdrproc_t encode;
@@ -876,23 +893,19 @@ call_encode(struct rpc_task *task)
(char *)req->rq_buffer + req->rq_callsize,
req->rq_rcvsize);
- /* Encode header and provided arguments */
- encode = task->tk_msg.rpc_proc->p_encode;
- if (!(p = call_header(task))) {
- printk(KERN_INFO "RPC: call_header failed, exit EIO\n");
+ p = rpc_encode_header(task);
+ if (p == NULL) {
+ printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n");
rpc_exit(task, -EIO);
return;
}
+
+ encode = task->tk_msg.rpc_proc->p_encode;
if (encode == NULL)
return;
task->tk_status = rpcauth_wrap_req(task, encode, req, p,
task->tk_msg.rpc_argp);
- if (task->tk_status == -ENOMEM) {
- /* XXX: Is this sane? */
- rpc_delay(task, 3*HZ);
- task->tk_status = -EAGAIN;
- }
}
/*
@@ -929,11 +942,9 @@ call_bind_status(struct rpc_task *task)
}
switch (task->tk_status) {
- case -EAGAIN:
- dprintk("RPC: %5u rpcbind waiting for another request "
- "to finish\n", task->tk_pid);
- /* avoid busy-waiting here -- could be a network outage. */
- rpc_delay(task, 5*HZ);
+ case -ENOMEM:
+ dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid);
+ rpc_delay(task, HZ >> 2);
goto retry_timeout;
case -EACCES:
dprintk("RPC: %5u remote rpcbind: RPC program/version "
@@ -1046,10 +1057,16 @@ call_transmit(struct rpc_task *task)
/* Encode here so that rpcsec_gss can use correct sequence number. */
if (rpc_task_need_encode(task)) {
BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
- call_encode(task);
+ rpc_xdr_encode(task);
/* Did the encode result in an error condition? */
- if (task->tk_status != 0)
+ if (task->tk_status != 0) {
+ /* Was the error nonfatal? */
+ if (task->tk_status == -EAGAIN)
+ rpc_delay(task, HZ >> 4);
+ else
+ rpc_exit(task, task->tk_status);
return;
+ }
}
xprt_transmit(task);
if (task->tk_status < 0)
@@ -1132,7 +1149,8 @@ call_status(struct rpc_task *task)
rpc_exit(task, status);
break;
default:
- printk("%s: RPC call returned error %d\n",
+ if (clnt->cl_chatty)
+ printk("%s: RPC call returned error %d\n",
clnt->cl_protname, -status);
rpc_exit(task, status);
}
@@ -1157,7 +1175,8 @@ call_timeout(struct rpc_task *task)
task->tk_timeouts++;
if (RPC_IS_SOFT(task)) {
- printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
+ if (clnt->cl_chatty)
+ printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
clnt->cl_protname, clnt->cl_server);
rpc_exit(task, -EIO);
return;
@@ -1165,7 +1184,8 @@ call_timeout(struct rpc_task *task)
if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
task->tk_flags |= RPC_CALL_MAJORSEEN;
- printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
+ if (clnt->cl_chatty)
+ printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
clnt->cl_protname, clnt->cl_server);
}
rpc_force_rebind(clnt);
@@ -1196,8 +1216,9 @@ call_decode(struct rpc_task *task)
task->tk_pid, task->tk_status);
if (task->tk_flags & RPC_CALL_MAJORSEEN) {
- printk(KERN_NOTICE "%s: server %s OK\n",
- clnt->cl_protname, clnt->cl_server);
+ if (clnt->cl_chatty)
+ printk(KERN_NOTICE "%s: server %s OK\n",
+ clnt->cl_protname, clnt->cl_server);
task->tk_flags &= ~RPC_CALL_MAJORSEEN;
}
@@ -1224,8 +1245,7 @@ call_decode(struct rpc_task *task)
goto out_retry;
}
- /* Verify the RPC header */
- p = call_verify(task);
+ p = rpc_verify_header(task);
if (IS_ERR(p)) {
if (p == ERR_PTR(-EAGAIN))
goto out_retry;
@@ -1243,7 +1263,7 @@ call_decode(struct rpc_task *task)
return;
out_retry:
task->tk_status = 0;
- /* Note: call_verify() may have freed the RPC slot */
+ /* Note: rpc_verify_header() may have freed the RPC slot */
if (task->tk_rqstp == req) {
req->rq_received = req->rq_rcv_buf.len = 0;
if (task->tk_client->cl_discrtry)
@@ -1290,11 +1310,8 @@ call_refreshresult(struct rpc_task *task)
return;
}
-/*
- * Call header serialization
- */
static __be32 *
-call_header(struct rpc_task *task)
+rpc_encode_header(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
struct rpc_rqst *req = task->tk_rqstp;
@@ -1314,11 +1331,8 @@ call_header(struct rpc_task *task)
return p;
}
-/*
- * Reply header verification
- */
static __be32 *
-call_verify(struct rpc_task *task)
+rpc_verify_header(struct rpc_task *task)
{
struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
@@ -1392,7 +1406,7 @@ call_verify(struct rpc_task *task)
task->tk_action = call_bind;
goto out_retry;
case RPC_AUTH_TOOWEAK:
- printk(KERN_NOTICE "call_verify: server %s requires stronger "
+ printk(KERN_NOTICE "RPC: server %s requires stronger "
"authentication.\n", task->tk_client->cl_server);
break;
default:
@@ -1431,10 +1445,10 @@ call_verify(struct rpc_task *task)
error = -EPROTONOSUPPORT;
goto out_err;
case RPC_PROC_UNAVAIL:
- dprintk("RPC: %5u %s: proc %p unsupported by program %u, "
+ dprintk("RPC: %5u %s: proc %s unsupported by program %u, "
"version %u on server %s\n",
task->tk_pid, __func__,
- task->tk_msg.rpc_proc,
+ rpc_proc_name(task),
task->tk_client->cl_prog,
task->tk_client->cl_vers,
task->tk_client->cl_server);
@@ -1517,44 +1531,53 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int
EXPORT_SYMBOL_GPL(rpc_call_null);
#ifdef RPC_DEBUG
+static void rpc_show_header(void)
+{
+ printk(KERN_INFO "-pid- flgs status -client- --rqstp- "
+ "-timeout ---ops--\n");
+}
+
+static void rpc_show_task(const struct rpc_clnt *clnt,
+ const struct rpc_task *task)
+{
+ const char *rpc_waitq = "none";
+ char *p, action[KSYM_SYMBOL_LEN];
+
+ if (RPC_IS_QUEUED(task))
+ rpc_waitq = rpc_qname(task->tk_waitqueue);
+
+ /* map tk_action pointer to a function name; then trim off
+ * the "+0x0 [sunrpc]" */
+ sprint_symbol(action, (unsigned long)task->tk_action);
+ p = strchr(action, '+');
+ if (p)
+ *p = '\0';
+
+ printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%s q:%s\n",
+ task->tk_pid, task->tk_flags, task->tk_status,
+ clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops,
+ clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task),
+ action, rpc_waitq);
+}
+
void rpc_show_tasks(void)
{
struct rpc_clnt *clnt;
- struct rpc_task *t;
+ struct rpc_task *task;
+ int header = 0;
spin_lock(&rpc_client_lock);
- if (list_empty(&all_clients))
- goto out;
- printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
- "-rpcwait -action- ---ops--\n");
list_for_each_entry(clnt, &all_clients, cl_clients) {
- if (list_empty(&clnt->cl_tasks))
- continue;
spin_lock(&clnt->cl_lock);
- list_for_each_entry(t, &clnt->cl_tasks, tk_task) {
- const char *rpc_waitq = "none";
- int proc;
-
- if (t->tk_msg.rpc_proc)
- proc = t->tk_msg.rpc_proc->p_proc;
- else
- proc = -1;
-
- if (RPC_IS_QUEUED(t))
- rpc_waitq = rpc_qname(t->tk_waitqueue);
-
- printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
- t->tk_pid, proc,
- t->tk_flags, t->tk_status,
- t->tk_client,
- (t->tk_client ? t->tk_client->cl_prog : 0),
- t->tk_rqstp, t->tk_timeout,
- rpc_waitq,
- t->tk_action, t->tk_ops);
+ list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
+ if (!header) {
+ rpc_show_header();
+ header++;
+ }
+ rpc_show_task(clnt, task);
}
spin_unlock(&clnt->cl_lock);
}
-out:
spin_unlock(&rpc_client_lock);
}
#endif
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index e6fb21b19b8..24db2b4d12d 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -32,6 +32,10 @@
#define RPCBIND_PROGRAM (100000u)
#define RPCBIND_PORT (111u)
+#define RPCBVERS_2 (2u)
+#define RPCBVERS_3 (3u)
+#define RPCBVERS_4 (4u)
+
enum {
RPCBPROC_NULL,
RPCBPROC_SET,
@@ -64,6 +68,7 @@ enum {
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
static void rpcb_getport_done(struct rpc_task *, void *);
+static void rpcb_map_release(void *data);
static struct rpc_program rpcb_program;
struct rpcbind_args {
@@ -76,41 +81,73 @@ struct rpcbind_args {
const char * r_netid;
const char * r_addr;
const char * r_owner;
+
+ int r_status;
};
static struct rpc_procinfo rpcb_procedures2[];
static struct rpc_procinfo rpcb_procedures3[];
+static struct rpc_procinfo rpcb_procedures4[];
struct rpcb_info {
- int rpc_vers;
+ u32 rpc_vers;
struct rpc_procinfo * rpc_proc;
};
static struct rpcb_info rpcb_next_version[];
static struct rpcb_info rpcb_next_version6[];
+static const struct rpc_call_ops rpcb_getport_ops = {
+ .rpc_call_done = rpcb_getport_done,
+ .rpc_release = rpcb_map_release,
+};
+
+static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
+{
+ xprt_clear_binding(xprt);
+ rpc_wake_up_status(&xprt->binding, status);
+}
+
static void rpcb_map_release(void *data)
{
struct rpcbind_args *map = data;
+ rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status);
xprt_put(map->r_xprt);
kfree(map);
}
-static const struct rpc_call_ops rpcb_getport_ops = {
- .rpc_call_done = rpcb_getport_done,
- .rpc_release = rpcb_map_release,
+static const struct sockaddr_in rpcb_inaddr_loopback = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ .sin_port = htons(RPCBIND_PORT),
};
-static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
+static const struct sockaddr_in6 rpcb_in6addr_loopback = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_LOOPBACK_INIT,
+ .sin6_port = htons(RPCBIND_PORT),
+};
+
+static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
+ size_t addrlen, u32 version)
{
- xprt_clear_binding(xprt);
- rpc_wake_up_status(&xprt->binding, status);
+ struct rpc_create_args args = {
+ .protocol = XPRT_TRANSPORT_UDP,
+ .address = addr,
+ .addrsize = addrlen,
+ .servername = "localhost",
+ .program = &rpcb_program,
+ .version = version,
+ .authflavor = RPC_AUTH_UNIX,
+ .flags = RPC_CLNT_CREATE_NOPING,
+ };
+
+ return rpc_create(&args);
}
static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
- size_t salen, int proto, u32 version,
- int privileged)
+ size_t salen, int proto, u32 version)
{
struct rpc_create_args args = {
.protocol = proto,
@@ -120,7 +157,8 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
.program = &rpcb_program,
.version = version,
.authflavor = RPC_AUTH_UNIX,
- .flags = RPC_CLNT_CREATE_NOPING,
+ .flags = (RPC_CLNT_CREATE_NOPING |
+ RPC_CLNT_CREATE_NONPRIVPORT),
};
switch (srvaddr->sa_family) {
@@ -134,29 +172,72 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
return NULL;
}
- if (!privileged)
- args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
return rpc_create(&args);
}
+static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
+ u32 version, struct rpc_message *msg,
+ int *result)
+{
+ struct rpc_clnt *rpcb_clnt;
+ int error = 0;
+
+ *result = 0;
+
+ rpcb_clnt = rpcb_create_local(addr, addrlen, version);
+ if (!IS_ERR(rpcb_clnt)) {
+ error = rpc_call_sync(rpcb_clnt, msg, 0);
+ rpc_shutdown_client(rpcb_clnt);
+ } else
+ error = PTR_ERR(rpcb_clnt);
+
+ if (error < 0)
+ printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+ "server (errno %d).\n", -error);
+ dprintk("RPC: registration status %d/%d\n", error, *result);
+
+ return error;
+}
+
/**
* rpcb_register - set or unset a port registration with the local rpcbind svc
* @prog: RPC program number to bind
* @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
+ * @prot: transport protocol to register
* @port: port value to register
- * @okay: result code
+ * @okay: OUT: result code
+ *
+ * RPC services invoke this function to advertise their contact
+ * information via the system's rpcbind daemon. RPC services
+ * invoke this function once for each [program, version, transport]
+ * tuple they wish to advertise.
+ *
+ * Callers may also unregister RPC services that are no longer
+ * available by setting the passed-in port to zero. This removes
+ * all registered transports for [program, version] from the local
+ * rpcbind database.
+ *
+ * Returns zero if the registration request was dispatched
+ * successfully and a reply was received. The rpcbind daemon's
+ * boolean result code is stored in *okay.
+ *
+ * Returns an errno value and sets *result to zero if there was
+ * some problem that prevented the rpcbind request from being
+ * dispatched, or if the rpcbind daemon did not respond within
+ * the timeout.
*
- * port == 0 means unregister, port != 0 means register.
+ * This function uses rpcbind protocol version 2 to contact the
+ * local rpcbind daemon.
*
- * This routine supports only rpcbind version 2.
+ * Registration works over both AF_INET and AF_INET6, and services
+ * registered via this function are advertised as available for any
+ * address. If the local rpcbind daemon is listening on AF_INET6,
+ * services registered via this function will be advertised on
+ * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
+ * addresses).
*/
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
{
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
- .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
- };
struct rpcbind_args map = {
.r_prog = prog,
.r_vers = vers,
@@ -164,32 +245,159 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
.r_port = port,
};
struct rpc_message msg = {
- .rpc_proc = &rpcb_procedures2[port ?
- RPCBPROC_SET : RPCBPROC_UNSET],
.rpc_argp = &map,
.rpc_resp = okay,
};
- struct rpc_clnt *rpcb_clnt;
- int error = 0;
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
"rpcbind\n", (port ? "" : "un"),
prog, vers, prot, port);
- rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
- sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1);
- if (IS_ERR(rpcb_clnt))
- return PTR_ERR(rpcb_clnt);
+ msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
+ if (port)
+ msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
- error = rpc_call_sync(rpcb_clnt, &msg, 0);
+ return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
+ sizeof(rpcb_inaddr_loopback),
+ RPCBVERS_2, &msg, okay);
+}
- rpc_shutdown_client(rpcb_clnt);
- if (error < 0)
- printk(KERN_WARNING "RPC: failed to contact local rpcbind "
- "server (errno %d).\n", -error);
- dprintk("RPC: registration status %d/%d\n", error, *okay);
+/*
+ * Fill in AF_INET family-specific arguments to register
+ */
+static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
+ struct rpc_message *msg)
+{
+ struct rpcbind_args *map = msg->rpc_argp;
+ unsigned short port = ntohs(address_to_register->sin_port);
+ char buf[32];
+
+ /* Construct AF_INET universal address */
+ snprintf(buf, sizeof(buf),
+ NIPQUAD_FMT".%u.%u",
+ NIPQUAD(address_to_register->sin_addr.s_addr),
+ port >> 8, port & 0xff);
+ map->r_addr = buf;
+
+ dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
+ "local rpcbind\n", (port ? "" : "un"),
+ map->r_prog, map->r_vers,
+ map->r_addr, map->r_netid);
+
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
+ if (port)
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+
+ return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
+ sizeof(rpcb_inaddr_loopback),
+ RPCBVERS_4, msg, msg->rpc_resp);
+}
- return error;
+/*
+ * Fill in AF_INET6 family-specific arguments to register
+ */
+static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
+ struct rpc_message *msg)
+{
+ struct rpcbind_args *map = msg->rpc_argp;
+ unsigned short port = ntohs(address_to_register->sin6_port);
+ char buf[64];
+
+ /* Construct AF_INET6 universal address */
+ snprintf(buf, sizeof(buf),
+ NIP6_FMT".%u.%u",
+ NIP6(address_to_register->sin6_addr),
+ port >> 8, port & 0xff);
+ map->r_addr = buf;
+
+ dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
+ "local rpcbind\n", (port ? "" : "un"),
+ map->r_prog, map->r_vers,
+ map->r_addr, map->r_netid);
+
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
+ if (port)
+ msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+
+ return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
+ sizeof(rpcb_in6addr_loopback),
+ RPCBVERS_4, msg, msg->rpc_resp);
+}
+
+/**
+ * rpcb_v4_register - set or unset a port registration with the local rpcbind
+ * @program: RPC program number of service to (un)register
+ * @version: RPC version number of service to (un)register
+ * @address: address family, IP address, and port to (un)register
+ * @netid: netid of transport protocol to (un)register
+ * @result: result code from rpcbind RPC call
+ *
+ * RPC services invoke this function to advertise their contact
+ * information via the system's rpcbind daemon. RPC services
+ * invoke this function once for each [program, version, address,
+ * netid] tuple they wish to advertise.
+ *
+ * Callers may also unregister RPC services that are no longer
+ * available by setting the port number in the passed-in address
+ * to zero. Callers pass a netid of "" to unregister all
+ * transport netids associated with [program, version, address].
+ *
+ * Returns zero if the registration request was dispatched
+ * successfully and a reply was received. The rpcbind daemon's
+ * result code is stored in *result.
+ *
+ * Returns an errno value and sets *result to zero if there was
+ * some problem that prevented the rpcbind request from being
+ * dispatched, or if the rpcbind daemon did not respond within
+ * the timeout.
+ *
+ * This function uses rpcbind protocol version 4 to contact the
+ * local rpcbind daemon. The local rpcbind daemon must support
+ * version 4 of the rpcbind protocol in order for these functions
+ * to register a service successfully.
+ *
+ * Supported netids include "udp" and "tcp" for UDP and TCP over
+ * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6,
+ * respectively.
+ *
+ * The contents of @address determine the address family and the
+ * port to be registered. The usual practice is to pass INADDR_ANY
+ * as the raw address, but specifying a non-zero address is also
+ * supported by this API if the caller wishes to advertise an RPC
+ * service on a specific network interface.
+ *
+ * Note that passing in INADDR_ANY does not create the same service
+ * registration as IN6ADDR_ANY. The former advertises an RPC
+ * service on any IPv4 address, but not on IPv6. The latter
+ * advertises the service on all IPv4 and IPv6 addresses.
+ */
+int rpcb_v4_register(const u32 program, const u32 version,
+ const struct sockaddr *address, const char *netid,
+ int *result)
+{
+ struct rpcbind_args map = {
+ .r_prog = program,
+ .r_vers = version,
+ .r_netid = netid,
+ .r_owner = RPCB_OWNER_STRING,
+ };
+ struct rpc_message msg = {
+ .rpc_argp = &map,
+ .rpc_resp = result,
+ };
+
+ *result = 0;
+
+ switch (address->sa_family) {
+ case AF_INET:
+ return rpcb_register_netid4((struct sockaddr_in *)address,
+ &msg);
+ case AF_INET6:
+ return rpcb_register_netid6((struct sockaddr_in6 *)address,
+ &msg);
+ }
+
+ return -EAFNOSUPPORT;
}
/**
@@ -227,7 +435,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
__func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
- sizeof(*sin), prot, 2, 0);
+ sizeof(*sin), prot, RPCBVERS_2);
if (IS_ERR(rpcb_clnt))
return PTR_ERR(rpcb_clnt);
@@ -289,17 +497,16 @@ void rpcb_getport_async(struct rpc_task *task)
/* Autobind on cloned rpc clients is discouraged */
BUG_ON(clnt->cl_parent != clnt);
+ /* Put self on the wait queue to ensure we get notified if
+ * some other task is already attempting to bind the port */
+ rpc_sleep_on(&xprt->binding, task, NULL);
+
if (xprt_test_and_set_binding(xprt)) {
- status = -EAGAIN; /* tell caller to check again */
dprintk("RPC: %5u %s: waiting for another binder\n",
task->tk_pid, __func__);
- goto bailout_nowake;
+ return;
}
- /* Put self on queue before sending rpcbind request, in case
- * rpcb_getport_done completes before we return from rpc_run_task */
- rpc_sleep_on(&xprt->binding, task, NULL);
-
/* Someone else may have bound if we slept */
if (xprt_bound(xprt)) {
status = 0;
@@ -338,7 +545,7 @@ void rpcb_getport_async(struct rpc_task *task)
task->tk_pid, __func__, bind_version);
rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
- bind_version, 0);
+ bind_version);
if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt);
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
@@ -361,15 +568,15 @@ void rpcb_getport_async(struct rpc_task *task)
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
+ map->r_status = -EIO;
child = rpcb_call_async(rpcb_clnt, map, proc);
rpc_release_client(rpcb_clnt);
if (IS_ERR(child)) {
- status = -EIO;
/* rpcb_map_release() has freed the arguments */
dprintk("RPC: %5u %s: rpc_run_task failed\n",
task->tk_pid, __func__);
- goto bailout_nofree;
+ return;
}
rpc_put_task(child);
@@ -378,7 +585,6 @@ void rpcb_getport_async(struct rpc_task *task)
bailout_nofree:
rpcb_wake_rpcbind_waiters(xprt, status);
-bailout_nowake:
task->tk_status = status;
}
EXPORT_SYMBOL_GPL(rpcb_getport_async);
@@ -417,9 +623,13 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
child->tk_pid, status, map->r_port);
- rpcb_wake_rpcbind_waiters(xprt, status);
+ map->r_status = status;
}
+/*
+ * XDR functions for rpcbind
+ */
+
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
struct rpcbind_args *rpcb)
{
@@ -438,7 +648,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
unsigned short *portp)
{
*portp = (unsigned short) ntohl(*p++);
- dprintk("RPC: rpcb_decode_getport result %u\n",
+ dprintk("RPC: rpcb_decode_getport result %u\n",
*portp);
return 0;
}
@@ -447,8 +657,8 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
unsigned int *boolp)
{
*boolp = (unsigned int) ntohl(*p++);
- dprintk("RPC: rpcb_decode_set result %u\n",
- *boolp);
+ dprintk("RPC: rpcb_decode_set: call %s\n",
+ (*boolp ? "succeeded" : "failed"));
return 0;
}
@@ -571,52 +781,60 @@ out_err:
static struct rpc_procinfo rpcb_procedures2[] = {
PROC(SET, mapping, set),
PROC(UNSET, mapping, set),
- PROC(GETADDR, mapping, getport),
+ PROC(GETPORT, mapping, getport),
};
static struct rpc_procinfo rpcb_procedures3[] = {
- PROC(SET, mapping, set),
- PROC(UNSET, mapping, set),
+ PROC(SET, getaddr, set),
+ PROC(UNSET, getaddr, set),
PROC(GETADDR, getaddr, getaddr),
};
static struct rpc_procinfo rpcb_procedures4[] = {
- PROC(SET, mapping, set),
- PROC(UNSET, mapping, set),
+ PROC(SET, getaddr, set),
+ PROC(UNSET, getaddr, set),
+ PROC(GETADDR, getaddr, getaddr),
PROC(GETVERSADDR, getaddr, getaddr),
};
static struct rpcb_info rpcb_next_version[] = {
-#ifdef CONFIG_SUNRPC_BIND34
- { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
- { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
-#endif
- { 2, &rpcb_procedures2[RPCBPROC_GETPORT] },
- { 0, NULL },
+ {
+ .rpc_vers = RPCBVERS_2,
+ .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT],
+ },
+ {
+ .rpc_proc = NULL,
+ },
};
static struct rpcb_info rpcb_next_version6[] = {
-#ifdef CONFIG_SUNRPC_BIND34
- { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
- { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
-#endif
- { 0, NULL },
+ {
+ .rpc_vers = RPCBVERS_4,
+ .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR],
+ },
+ {
+ .rpc_vers = RPCBVERS_3,
+ .rpc_proc = &rpcb_procedures3[RPCBPROC_GETADDR],
+ },
+ {
+ .rpc_proc = NULL,
+ },
};
static struct rpc_version rpcb_version2 = {
- .number = 2,
+ .number = RPCBVERS_2,
.nrprocs = RPCB_HIGHPROC_2,
.procs = rpcb_procedures2
};
static struct rpc_version rpcb_version3 = {
- .number = 3,
+ .number = RPCBVERS_3,
.nrprocs = RPCB_HIGHPROC_3,
.procs = rpcb_procedures3
};
static struct rpc_version rpcb_version4 = {
- .number = 4,
+ .number = RPCBVERS_4,
.nrprocs = RPCB_HIGHPROC_4,
.procs = rpcb_procedures4
};
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 6eab9bf94ba..385f427beda 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -576,9 +576,7 @@ EXPORT_SYMBOL_GPL(rpc_delay);
*/
static void rpc_prepare_task(struct rpc_task *task)
{
- lock_kernel();
task->tk_ops->rpc_call_prepare(task, task->tk_calldata);
- unlock_kernel();
}
/*
@@ -588,9 +586,7 @@ void rpc_exit_task(struct rpc_task *task)
{
task->tk_action = NULL;
if (task->tk_ops->rpc_call_done != NULL) {
- lock_kernel();
task->tk_ops->rpc_call_done(task, task->tk_calldata);
- unlock_kernel();
if (task->tk_action != NULL) {
WARN_ON(RPC_ASSASSINATED(task));
/* Always release the RPC slot and buffer memory */
@@ -602,11 +598,8 @@ EXPORT_SYMBOL_GPL(rpc_exit_task);
void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
{
- if (ops->rpc_release != NULL) {
- lock_kernel();
+ if (ops->rpc_release != NULL)
ops->rpc_release(calldata);
- unlock_kernel();
- }
}
/*
@@ -626,19 +619,15 @@ static void __rpc_execute(struct rpc_task *task)
/*
* Execute any pending callback.
*/
- if (RPC_DO_CALLBACK(task)) {
- /* Define a callback save pointer */
+ if (task->tk_callback) {
void (*save_callback)(struct rpc_task *);
/*
- * If a callback exists, save it, reset it,
- * call it.
- * The save is needed to stop from resetting
- * another callback set within the callback handler
- * - Dave
+ * We set tk_callback to NULL before calling it,
+ * in case it sets the tk_callback field itself:
*/
- save_callback=task->tk_callback;
- task->tk_callback=NULL;
+ save_callback = task->tk_callback;
+ task->tk_callback = NULL;
save_callback(task);
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index e1770f7ba0b..99a52aabe33 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -690,7 +690,7 @@ static void xprt_connect_status(struct rpc_task *task)
{
struct rpc_xprt *xprt = task->tk_xprt;
- if (task->tk_status >= 0) {
+ if (task->tk_status == 0) {
xprt->stat.connect_count++;
xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start;
dprintk("RPC: %5u xprt_connect_status: connection established\n",
@@ -699,12 +699,6 @@ static void xprt_connect_status(struct rpc_task *task)
}
switch (task->tk_status) {
- case -ECONNREFUSED:
- case -ECONNRESET:
- dprintk("RPC: %5u xprt_connect_status: server %s refused "
- "connection\n", task->tk_pid,
- task->tk_client->cl_server);
- break;
case -ENOTCONN:
dprintk("RPC: %5u xprt_connect_status: connection broken\n",
task->tk_pid);
@@ -878,6 +872,7 @@ void xprt_transmit(struct rpc_task *task)
return;
req->rq_connect_cookie = xprt->connect_cookie;
+ req->rq_xtime = jiffies;
status = xprt->ops->send_request(task);
if (status == 0) {
dprintk("RPC: %5u xmit complete\n", task->tk_pid);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index ddbe981ab51..4486c59c3ac 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -579,7 +579,6 @@ static int xs_udp_send_request(struct rpc_task *task)
req->rq_svec->iov_base,
req->rq_svec->iov_len);
- req->rq_xtime = jiffies;
status = xs_sendpages(transport->sock,
xs_addr(xprt),
xprt->addrlen, xdr,
@@ -671,7 +670,6 @@ static int xs_tcp_send_request(struct rpc_task *task)
* to cope with writespace callbacks arriving _after_ we have
* called sendmsg(). */
while (1) {
- req->rq_xtime = jiffies;
status = xs_sendpages(transport->sock,
NULL, 0, xdr, req->rq_bytes_sent);