bk://kernel.bkbits.net/gregkh/linux/i2c-2.6
johnpol@2ka.mipt.ru[gregkh]|ChangeSet|20050329071647|01357 johnpol

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/28 23:16:47-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] connector: use NLMSG_SPACE macros for message size check.
#   
#   Use NLMSG_SPACE macros for message size check.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/connector/connector.c
#   2005/03/28 23:13:44-08:00 johnpol@2ka.mipt.ru +4 -5
#   connector: use NLMSG_SPACE macros for message size check.
# 
# ChangeSet
#   2005/03/28 21:25:09-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] connector: Documentation, usage cases, interface description.
#   
#   Documentation bits for kernel connector.
#   Test module which shows usage cases [lives in Documentation/connector].
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/connector/connector.txt
#   2005/03/21 23:54:49-08:00 johnpol@2ka.mipt.ru +154 -0
#   connector: Documentation, usage cases, interface description.
# 
# Documentation/connector/cn_test.c
#   2005/03/21 23:08:49-08:00 johnpol@2ka.mipt.ru +203 -0
#   connector: Documentation, usage cases, interface description.
# 
# Documentation/connector/connector.txt
#   2005/03/21 23:54:49-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/connector/connector.txt
# 
# Documentation/connector/cn_test.c
#   2005/03/21 23:08:49-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/connector/cn_test.c
# 
# ChangeSet
#   2005/03/28 21:22:40-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] w1_smem: w1 ID is only 8 bytes long.
#   
#   w1 ID is only 8 bytes long.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/w1/w1_smem.c
#   2005/03/28 16:00:00-08:00 johnpol@2ka.mipt.ru +2 -2
#   w1_smem: w1 ID is only 8 bytes long.
# 
# ChangeSet
#   2005/03/28 21:22:17-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] w1: real fix for big endian machines.
#   
#   Real fix for big endian machines - crc must be calculated
#   using little endian byte order.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/w1/w1.c
#   2005/02/28 02:01:39-08:00 johnpol@2ka.mipt.ru +5 -4
#   w1: real fix for big endian machines.
# 
# ChangeSet
#   2005/03/28 13:04:30-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Fix indentation of lm87 driver
#   
#   This trivial patch fixes indentation in the lm87 driver. I need this
#   'cause I'll soon post patches affecting these portions of code, and I'd
#   like these patches to be easily readable.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/lm87.c
#   2005/03/25 02:40:36-08:00 khali@linux-fr.org +10 -10
#   I2C: Fix indentation of lm87 driver
# 
# ChangeSet
#   2005/03/28 13:04:11-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Fix broken force parameter handling
#   
#   I just noticed a nasty bug in the way the "force" parameter is handled
#   for non-sensors i2c chip drivers. The "force" parameter supposedy is a
#   list of adapter, address *pairs* where supported chips are
#   unquestionably assumed to be. However, after handling one pair, the i2c
#   core code searches for the next one *three* values later, not two. So
#   with the current code, the second and third pairs wouldn't be properly
#   handled. The fourth one would be, and so on.
#   
#   As a side note, this questions the need of an array parameter handling
#   up to 24 of such pairs, when obviously nobody ever required more than
#   one for the past 6 years.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/i2c-core.c
#   2005/03/27 08:53:02-08:00 khali@linux-fr.org +1 -1
#   I2C: Fix broken force parameter handling
# 
# ChangeSet
#   2005/03/28 13:03:55-08:00 khali@linux-fr.org 
#   [PATCH] i2c: add adt7461 chip support to lm90 driver's Kconfig entry
#   
#   Hi Greg, James, all,
#   
#   > > > Attached is another version of my adt7461 patch, for inclusion in
#   > > > the 2.6 tree. Reviewed by Jean.
#   >
#   > May we have an additional patch to Kconfig for this one?
#   
#   Here it finally comes.
#   
#   This simple patch adds a mention to the ADT7461 chip in Kconfig, now
#   that the lm90 driver supports it.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/Kconfig
#   2005/03/27 04:33:02-08:00 khali@linux-fr.org +3 -0
#   i2c: add adt7461 chip support to lm90 driver's Kconfig entry
# 
# ChangeSet
#   2005/03/28 13:03:38-08:00 khali@linux-fr.org 
#   [PATCH] I2C: i2c-s3c2410 functionality and fixes
#   
#   This patch does the following updates to the i2c-s3c2410 bus driver:
#   
#   * Properly report the i2c functionality by adding to the
#     `.functionality` field of the adapter
#   
#   * Change the dev_err() call on no-ack to an dev_dbg() to make
#     it less noisy when the bus is being probed by i2cdetect, etc.
#   
#   * Add I2C_M_REV_DIR_ADDR to fully implement the
#     I2C_FUNC_PROTOCOLO_MANGLING.
#   
#   * Ensure that the adapter owner field is set to THIS_MODULE
#   
#   Please apply, thanks.
#   
#   (Once this is applied, all i2c bus drivers will be properly reporting
#   their functionality so I'll be able to go on with the i2c functionality
#   core cleanups.)
#   
#   Signed-off-by: Ben Dooks <ben-linux@fluff.org>
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/i2c-s3c2410.c
#   2005/03/26 10:02:15-08:00 khali@linux-fr.org +13 -2
#   I2C: i2c-s3c2410 functionality and fixes
# 
# ChangeSet
#   2005/03/28 13:03:17-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Fix race condition in it87 driver
#   
#   I noticed a race condition in the it87, affecting the IT8712F chip only.
#   The VRM value is currently initialized *after* creating the vrm and vid
#   sysfs files. This leaves a theorical room for reading from these files
#   and get an invalid value. It's not critical, but let's still fix it.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/it87.c
#   2005/03/24 06:08:24-08:00 khali@linux-fr.org +1 -1
#   I2C: Fix race condition in it87 driver
# 
# ChangeSet
#   2005/03/28 13:02:54-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Delete useless instruction in it87
#   
#   The IT8705F doesn't support VID, so it's quite pointless to give a value
#   to it (and an arbitrary one at that). I think that this instruction was
#   there for compatibility reasons some times ago, but the reasons went
#   away while the instruction was left in place. We can safely delete it
#   now.
#   
#   Thanks to Rudolf Marek for testing the patch (you never know).
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/it87.c
#   2005/03/24 06:06:35-08:00 khali@linux-fr.org +0 -3
#   I2C: Delete useless instruction in it87
# 
# ChangeSet
#   2005/03/23 19:37:35-08:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6
#   into bix.(none):/usr/src/bk-i2c
# 
# drivers/i2c/chips/eeprom.c
#   2005/03/23 19:37:31-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/23 16:12:04-08:00 rafael.espindola@gmail.com 
#   [PATCH] I2C: lsb in emc6d102 and adm1027
#   
#   The attached patches add support for reading the lsb from the emc6d102
#   and change how they are read from the adm1027.
#   
#   The lm85_update_device function decodes the LSBs to temp_ext and in_ext.
#   This strategy was suggested by Philip Pokorny.
#   
#   The patch also changes some macros to use the SCALE macro. I think that
#   they become more readable this way.
#   
#   
#   Signed-off-by: Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/lm85.c
#   2005/03/23 16:00:00-08:00 rafael.espindola@gmail.com +77 -23
#   I2C: lsb in emc6d102 and adm1027
# 
# ChangeSet
#   2005/03/23 16:11:37-08:00 ebrower@gmail.com 
#   [PATCH] I2C: lost arbitration detection for PCF8584
#   
#   [PATCH] lost arbitration detection for PCF8584 algo driver
#   
#   Patch against a slightly-dated linux-2.6 BK tree
#   
#   This patch provides lost arbitration detection for the PCF8584
#   I2C algorithm driver.  The PCF8584 LAB bit is set whenever lost
#   arbitration is detected, so we check the bit in the wait_for_pin
#   function and if LAB is detected we return -EINTR.  The -EINTR
#   value bubbles-up all the way to the master_xfer API call so
#   callers may detect this condition explicitly.  LAB could be checked
#   more often, at the expense of code readability/maintainability.
#   
#   Signed-off-by: Eric Brower <ebrower@gmail.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/algos/i2c-algo-pcf.c
#   2005/02/11 17:50:20-08:00 ebrower@gmail.com +41 -3
#   I2C: lost arbitration detection for PCF8584
# 
# ChangeSet
#   2005/03/23 16:10:58-08:00 R.Marek@sh.cvut.cz 
#   [PATCH] I2C: busses documentation update 2 of 2
#   
#   Patch contains promised documentation update for i2c bus drivers.
#   I would like to thank Jean Delvare and Aurelien Jarno for their
#   comments.
#   
#   Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/i2c/busses/scx200_acb
#   2005/02/17 15:29:54-08:00 R.Marek@sh.cvut.cz +14 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-voodoo3
#   2005/02/24 08:22:14-08:00 R.Marek@sh.cvut.cz +62 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-via
#   2005/02/24 08:21:17-08:00 R.Marek@sh.cvut.cz +34 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-viapro
#   2005/02/24 08:21:27-08:00 R.Marek@sh.cvut.cz +47 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-sis69x
#   2005/03/04 11:22:32-08:00 R.Marek@sh.cvut.cz +73 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-sis630
#   2005/03/04 11:20:53-08:00 R.Marek@sh.cvut.cz +49 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-sis5595
#   2005/03/04 11:18:39-08:00 R.Marek@sh.cvut.cz +59 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-savage4
#   2005/02/24 08:19:09-08:00 R.Marek@sh.cvut.cz +26 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-prosavage
#   2005/02/24 08:19:01-08:00 R.Marek@sh.cvut.cz +23 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-piix4
#   2005/03/04 11:18:10-08:00 R.Marek@sh.cvut.cz +72 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-pca-isa
#   2005/02/17 15:29:53-08:00 R.Marek@sh.cvut.cz +23 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-parport-light
#   2005/03/04 11:23:31-08:00 R.Marek@sh.cvut.cz +11 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-nforce2
#   2005/02/24 08:17:48-08:00 R.Marek@sh.cvut.cz +41 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-i810
#   2005/02/24 08:14:29-08:00 R.Marek@sh.cvut.cz +46 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-i801
#   2005/02/24 08:13:42-08:00 R.Marek@sh.cvut.cz +80 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-amd8111
#   2005/02/24 08:13:13-08:00 R.Marek@sh.cvut.cz +41 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-amd756
#   2005/02/24 08:12:32-08:00 R.Marek@sh.cvut.cz +25 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-ali15x3
#   2005/03/04 11:14:39-08:00 R.Marek@sh.cvut.cz +112 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-ali1563
#   2005/03/04 11:16:10-08:00 R.Marek@sh.cvut.cz +27 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-ali1535
#   2005/02/24 08:07:40-08:00 R.Marek@sh.cvut.cz +42 -0
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/scx200_acb
#   2005/02/17 15:29:54-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/scx200_acb
# 
# Documentation/i2c/busses/i2c-voodoo3
#   2005/02/24 08:22:14-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-voodoo3
# 
# Documentation/i2c/busses/i2c-via
#   2005/02/24 08:21:17-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-via
# 
# Documentation/i2c/busses/i2c-viapro
#   2005/02/24 08:21:27-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-viapro
# 
# Documentation/i2c/busses/i2c-sis69x
#   2005/03/04 11:22:32-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-sis69x
# 
# Documentation/i2c/busses/i2c-sis630
#   2005/03/04 11:20:53-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-sis630
# 
# Documentation/i2c/busses/i2c-sis5595
#   2005/03/04 11:18:39-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-sis5595
# 
# Documentation/i2c/busses/i2c-savage4
#   2005/02/24 08:19:09-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-savage4
# 
# Documentation/i2c/busses/i2c-prosavage
#   2005/02/24 08:19:01-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-prosavage
# 
# Documentation/i2c/busses/i2c-piix4
#   2005/03/04 11:18:10-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-piix4
# 
# Documentation/i2c/busses/i2c-pca-isa
#   2005/02/17 15:29:53-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-pca-isa
# 
# Documentation/i2c/busses/i2c-parport
#   2005/02/24 08:18:08-08:00 R.Marek@sh.cvut.cz +8 -10
#   I2C: busses documentation update 2 of 2
# 
# Documentation/i2c/busses/i2c-parport-light
#   2005/03/04 11:23:31-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-parport-light
# 
# Documentation/i2c/busses/i2c-nforce2
#   2005/02/24 08:17:48-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-nforce2
# 
# Documentation/i2c/busses/i2c-i810
#   2005/02/24 08:14:29-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-i810
# 
# Documentation/i2c/busses/i2c-i801
#   2005/02/24 08:13:42-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-i801
# 
# Documentation/i2c/busses/i2c-amd8111
#   2005/02/24 08:13:13-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-amd8111
# 
# Documentation/i2c/busses/i2c-amd756
#   2005/02/24 08:12:32-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-amd756
# 
# Documentation/i2c/busses/i2c-ali15x3
#   2005/03/04 11:14:39-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-ali15x3
# 
# Documentation/i2c/busses/i2c-ali1563
#   2005/03/04 11:16:10-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-ali1563
# 
# Documentation/i2c/busses/i2c-ali1535
#   2005/02/24 08:07:40-08:00 R.Marek@sh.cvut.cz +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/Documentation/i2c/busses/i2c-ali1535
# 
# ChangeSet
#   2005/03/23 16:10:36-08:00 R.Marek@sh.cvut.cz 
#   [PATCH] I2C: busses documentation update 1 of 2
#   
#   This patch just moves i2c-parport file to busses directory.
#   Patch for other busses documentation will follow.
#   
#   Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# Documentation/i2c/busses/i2c-parport
#   2005/02/17 15:29:53-08:00 R.Marek@sh.cvut.cz +0 -0
#   I2C: busses documentation update 1 of 2
# 
# ChangeSet
#   2005/03/23 15:55:45-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Fix Vaio EEPROM detection
#   
#   This fixes a bug in the eeprom driver, which made all EEPROMs at
#   location 0x57 be erroneously treated as Vaio EEPROMs. I have to say I'm
#   quite ashamed that I introduced the bug in the first place, as this was
#   a really stupid one.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/eeprom.c
#   2005/03/17 06:33:29-08:00 khali@linux-fr.org +2 -1
#   I2C: Fix Vaio EEPROM detection
# 
# ChangeSet
#   2005/03/23 15:55:25-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Recognize new revision of the ADT7463 chip
#   
#   This simple patch to the lm85 driver adds recognition of a new revision
#   of the ADT7463 chip.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/lm85.c
#   2005/03/18 14:03:42-08:00 khali@linux-fr.org +3 -1
#   I2C: Recognize new revision of the ADT7463 chip
# 
# ChangeSet
#   2005/03/23 15:55:04-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Avoid repeated resets of i2c-viapro
#   
#   It was reported that the i2c-viapro SMBus driver sometimes has trouble
#   on recent systems (VT8237 south bridge). The "Host Status" register has
#   at least one additional bit used when compared with older south bridges
#   of this family. The driver currently considers this additional bit as an
#   error condition when it's set, causing repeated bus resets and sometimes
#   read failures.
#   
#   This patch makes the driver ignore the bits of the "Host Status"
#   register for which no definition is known. I wish I had a datasheet for
#   the VIA VT8237, so that I could check what the additional bit is
#   supposed to mean, but I don't. If someone has a datasheet or good
#   contacts at VIA, please let me know.
#   
#   The patch was reported to fix the problem on a system with the VT8237,
#   and was also tested not to break the driver on older VIA south bridges,
#   so it seems to be safe. Thanks to Aurelien Jarno for the tests.
#   
#   Additionally, the patch makes the post-transaction bus reset slightly
#   more efficient by sparing a few unneeded I/O operations.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/i2c-viapro.c
#   2005/03/13 11:05:46-08:00 khali@linux-fr.org +9 -8
#   I2C: Avoid repeated resets of i2c-viapro
# 
# ChangeSet
#   2005/03/23 15:54:45-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Kill outdated defines in i2c.h
#   
#   Some defines in i2c.h (I2C_CLIENT_MODPARM and friends) are now useless.
#   They should have been removed when the i2c client parameters were
#   converted from MODULE_PARAM to module_parm_array, but where not. This
#   patch removes them now.
#   
#   Additionally, it moves the definition of I2C_CLIENT_MAX_OPTS next to
#   where it is used rather than 220 lines before, which is preferable IMHO.
#   
#   As a side note, I think that there is a bug in the way these options are
#   handled. The i2c code looks for I2C_CLIENT_END as a list terminator, but
#   if the maximum number of parameters are actually provided, no terminator
#   will be left. It's rather unlikely to happen because nobody will
#   probably ever provide that many parameters, but this should probably be
#   fixed. I'll address this issue later, since I plan to completely rewrite
#   the way these parameters are handled anyway.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/i2c.h
#   2005/03/20 03:26:34-08:00 khali@linux-fr.org +3 -10
#   I2C: Kill outdated defines in i2c.h
# 
# ChangeSet
#   2005/03/23 15:54:02-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Fix some i2c algorithm initialization
#   
#   While searching for i2c_algorithm declarations missing their
#   .functionality member, I found three of them which were not properly
#   initialized. i2c-algo-ite and i2c_sibyte_algo do not use the C99
#   initialization syntax, and i2c-ibm_iic.c explicitely initializes NULL
#   members. Following patch puts some order in there.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/i2c-ibm_iic.c
#   2005/03/23 07:59:21-08:00 khali@linux-fr.org +0 -4
#   I2C: Fix some i2c algorithm initialization
# 
# drivers/i2c/algos/i2c-algo-sibyte.c
#   2005/03/23 08:07:04-08:00 khali@linux-fr.org +5 -8
#   I2C: Fix some i2c algorithm initialization
# 
# drivers/i2c/algos/i2c-algo-ite.c
#   2005/03/23 08:09:51-08:00 khali@linux-fr.org +5 -8
#   I2C: Fix some i2c algorithm initialization
# 
# ChangeSet
#   2005/03/16 22:58:37-08:00 mgreer@mvista.com 
#   [PATCH] I2C: Fix breakage in m41t00 i2c rtc driver
#   
#   Remove setting of deleted i2c_client structure member.
#   
#   The latest include/linux/i2c.h:i2c_client structure no longer has an
#   'id' member.  This patch removes the setting of that no longer existing
#   member.
#   
#   Signed-off-by: Mark A. Greer <mgreer@mvista.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/m41t00.c
#   2005/03/08 16:18:24-08:00 mgreer@mvista.com +0 -1
#   I2C: Fix breakage in m41t00 i2c rtc driver
# 
# ChangeSet
#   2005/03/16 22:58:09-08:00 frank.beesley@aeroflex.com 
#   [PATCH] I2C: Clean up of i2c-elektor.c build
#   
#   This patch changes the flags variable type from long to unsigned long in
#   one function. This removes a couple of warnings from the compile
#   messages for elektor i2c bus driver.
#   
#   Signed-off-by: Frank Beesley <frank.beesley@aeroflex.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/i2c-elektor.c
#   2005/03/11 12:03:44-08:00 frank.beesley@aeroflex.com +1 -1
#   I2C: Clean up of i2c-elektor.c build
# 
# ChangeSet
#   2005/03/16 22:54:03-08:00 jchapman@katalix.com 
#   [PATCH] i2c: add adt7461 chip support to lm90 driver
#   
#   i2c: add adt7461 chip support
#   
#   The Analog Devices ADT7461 temperature sensor chip is compatible with
#   the lm90 device provided its extended temperature range is not
#   enabled.  The chip will be ignored if the boot firmware enables
#   extended temperature range.
#   
#   Also, since the adt7461 treats temp values <0 as 0 and >127 as 127,
#   the driver prevents temperature values outside the supported range
#   from being set.
#   
#   Signed-off-by: James Chapman <jchapman@katalix.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/lm90.c
#   2005/03/16 22:51:41-08:00 jchapman@katalix.com +41 -3
#   i2c: add adt7461 chip support to lm90 driver
# 
# ChangeSet
#   2005/03/16 22:49:47-08:00 jchapman@katalix.com 
#   [PATCH] i2c: new driver for ds1337 RTC
#   
#   Signed-off-by: James Chapman <jchapman@katalix.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/ds1337.c
#   2005/03/07 02:33:52-08:00 jchapman@katalix.com +402 -0
#   i2c: new driver for ds1337 RTC
# 
# drivers/i2c/chips/Makefile
#   2005/03/04 08:59:53-08:00 jchapman@katalix.com +1 -0
#   i2c: new driver for ds1337 RTC
# 
# drivers/i2c/chips/Kconfig
#   2005/03/04 08:59:53-08:00 jchapman@katalix.com +11 -0
#   i2c: new driver for ds1337 RTC
# 
# drivers/i2c/chips/ds1337.c
#   2005/03/07 02:33:52-08:00 jchapman@katalix.com +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/ds1337.c
# 
# ChangeSet
#   2005/03/16 22:39:26-08:00 grant_nospam@dodo.com.au 
#   [PATCH] I2C: group Intel on I2C Hardware Bus support
#   
#    From an end-user perspective it is easy to miss the third Intel PIIX
#   entry on the menuconfig "I2C Hardware Bus support" screen.
#   Also the Intel 801 menu item does not mention ICH.
#   
#   This trivial patch groups three Intel entries together, adds ICH to
#   menu item, and ICH5/ICH5R to the help section.  Includes suggestions
#   from Jean Delvare.
#   
#   Signed-off-by: Grant Coady <gcoady@gmail.com>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/Kconfig
#   2005/03/16 14:45:14-08:00 grant_nospam@dodo.com.au +19 -19
#   I2C: group Intel on I2C Hardware Bus support
# 
# ChangeSet
#   2005/03/16 22:39:00-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Skip broken detection step in it87
#   
#   One of the detection steps in the it87 chip driver was reported to be
#   broken for some revisions of the IT8712F chip [1] [2]. This detection
#   step is a legacy from the lm78 driver and the documentation available
#   for the IT8705F and IT8712F chips does not mention it at all. For this
#   reason, I propose to skip this detection step for Super-I/O chips.
#   Super-I/O chips have already been identified when we reach this step, so
#   it is redundant (additionally do being broken). This closes bug #4335.
#   
#   [1] http://bugzilla.kernel.org/show_bug.cgi?id=4335
#   [2] http://archives.andrew.net.au/lm-sensors/msg29962.html
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/it87.c
#   2005/03/15 11:51:14-08:00 khali@linux-fr.org +2 -3
#   I2C: Skip broken detection step in it87
# 
# ChangeSet
#   2005/03/16 22:38:32-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Make master_xfer debug messages more useful
#   
#   While working on the recent saa7110 mess, I found that the debug message
#   displayed when calling master_xfer wasn't as useful as it could be. Here
#   is a patch improving this.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/i2c-core.c
#   2005/03/08 10:06:36-08:00 khali@linux-fr.org +7 -1
#   I2C: Make master_xfer debug messages more useful
# 
# ChangeSet
#   2005/03/16 22:38:06-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Kill unused struct members in w83627hf driver
#   
#   I just noticed that the pwmenable struct members in the w83627hf driver
#   are not used anywhere (and quite rightly so, as PWM cannot be disabled
#   in these chips as far as I know). Let's just get rid of them and save
#   some bytes of memory.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/w83627hf.c
#   2005/03/07 02:56:22-08:00 khali@linux-fr.org +0 -5
#   I2C: Kill unused struct members in w83627hf driver
# 
# ChangeSet
#   2005/03/16 22:37:40-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Fix adm1021 alarms mask
#   
#   This patch fixes an incorrect bitmasking on the status register in the
#   adm1021 driver, which was causing high alarm on remote temperature to be
#   hidden.
#   This bug was found and reported by Jayakrishnan:
#     http://bugzilla.kernel.org/show_bug.cgi?id=4285
#   
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/adm1021.c
#   2005/03/04 05:03:33-08:00 khali@linux-fr.org +1 -1
#   I2C: Fix adm1021 alarms mask
# 
# ChangeSet
#   2005/03/16 22:37:17-08:00 khali@linux-fr.org 
#   [PATCH] I2C: Cleanup adm1021 unused defines
#   
#   While working on the adm1021 driver, I found that this driver has a
#   number of unused (and useless) defines we could get rid of.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/adm1021.c
#   2005/03/04 05:24:16-08:00 khali@linux-fr.org +0 -12
#   I2C: Cleanup adm1021 unused defines
# 
# ChangeSet
#   2005/03/16 22:36:58-08:00 khali@linux-fr.org 
#   [PATCH] I2C: New lm92 chip driver
#   
#   This is a new i2c chip driver named lm92. It supports the National
#   Semiconductor LM92 and Maxim MAX6635 chips. This time I did not port the
#   driver from the lm_sensors project but instead rewrote it. The reason is
#   that the original driver has a different structure from the other i2c
#   chip drivers, which would have made maintenance harder.
#   
#   I don't have a compatible chip myself but could test my code thanks to
#   Mark Hoffman's i2c-stub fake bus driver. Later on, James Chapman tested
#   it on a real chip, successfully.
#   
#   Signed-off-by: Jean Delvare <khali@linux-fr.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/chips/lm92.c
#   2005/03/06 00:19:47-08:00 khali@linux-fr.org +423 -0
#   I2C: New lm92 chip driver
# 
# drivers/i2c/chips/lm92.c
#   2005/03/06 00:19:47-08:00 khali@linux-fr.org +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/lm92.c
# 
# drivers/i2c/chips/Makefile
#   2005/03/06 00:19:47-08:00 khali@linux-fr.org +1 -0
#   I2C: New lm92 chip driver
# 
# drivers/i2c/chips/Kconfig
#   2005/03/06 00:19:47-08:00 khali@linux-fr.org +11 -0
#   I2C: New lm92 chip driver
# 
# ChangeSet
#   2005/03/16 22:36:33-08:00 domen@coderock.org 
#   [PATCH] i2c/i2c-elektor: remove interruptible_sleep_on_timeout() usage
#   
#   Replace deprecated interruptible_sleep_on_timeout() with direct
#   wait-queue usage. Patch is compile-tested.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/i2c-elektor.c
#   2005/03/05 07:12:06-08:00 domen@coderock.org +4 -3
#   i2c/i2c-elektor: remove interruptible_sleep_on_timeout() usage
# 
# ChangeSet
#   2005/03/16 22:36:08-08:00 domen@coderock.org 
#   [PATCH] i2c/i2c-ite: remove interruptible_sleep_on_timeout() usage
#   
#   Replace deprecated interruptible_sleep_on_timeout() with direct
#   wait-queue usage. Patch is compile-tested, sort of; the driver does not build in
#   vanilla kernel either, but I don't seem to add any warnings..
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/i2c/busses/i2c-ite.c
#   2005/03/05 07:12:07-08:00 domen@coderock.org +5 -2
#   i2c/i2c-ite: remove interruptible_sleep_on_timeout() usage
# 
# ChangeSet
#   2005/03/14 21:31:27-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] superio: get rid of the potential problems with atomic operations.
#   
#   Get rid of the potential problems with atomic operations.
#   
#   According to upcoming atomic_ops.txt by David Miller and Anton Blanchard
#   some archs may reoder atomic operations with nonatomic, since
#   the former are always visible but the latter are not, this can lead
#   to unpredicted behaviour.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/superio/sc.c
#   2005/03/02 09:56:38-08:00 johnpol@2ka.mipt.ru +24 -2
#   superio: get rid of the potential problems with atomic operations.
# 
# ChangeSet
#   2005/03/14 21:31:01-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] kobject_uevent: prefill allocated buffer with 0 before use.
#   
#   Prefill allocated buffer with 0 before use.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# lib/kobject_uevent.c
#   2005/03/02 09:56:56-08:00 johnpol@2ka.mipt.ru +2 -0
#   kobject_uevent: prefill allocated buffer with 0 before use.
# 
# ChangeSet
#   2005/03/14 21:30:28-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] connector: fix skb leak on big messages.
#   
#   If message size exceeds CONNECTOR_MAX_MSG_SIZE skb can be leaked.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/connector/connector.c
#   2005/03/02 09:57:02-08:00 johnpol@2ka.mipt.ru +7 -2
#   connector: fix skb leak on big messages.
# 
# ChangeSet
#   2005/03/14 21:29:59-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] connector: allow sent to self messages.
#   
#   Allow sending messages to itself.
#   Since netlink sending routing do not allow(will not allow)
#   shared skb, we will clone original skb, if it fails
#   skb will be delivered only to remote groups.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/connector/connector.c
#   2005/03/02 09:57:09-08:00 johnpol@2ka.mipt.ru +9 -2
#   connector: allow sent to self messages.
# 
# ChangeSet
#   2005/03/14 21:29:24-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] connector: get rid of the potential problems with atomic operations.
#   
#   Get rid of the potential problems with atomic operations.
#   
#   According to upcoming atomic_ops.txt by David Miller and Anton Blanchard
#   some archs may reoder atomic operations with nonatomic, since
#   the former are always visible but the latter are not, this can lead
#   to unpredicted behaviour.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/connector/cn_queue.c
#   2005/03/02 09:57:18-08:00 johnpol@2ka.mipt.ru +14 -2
#   connector: get rid of the potential problems with atomic operations.
# 
# ChangeSet
#   2005/03/14 21:28:54-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] connector: Use DEFINE_SPINLOCK.
#   
#   Use DEFINE_SPINLOCK for private connector's notify lock.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/connector/connector.c
#   2005/03/02 09:58:14-08:00 johnpol@2ka.mipt.ru +1 -1
#   connector: Use DEFINE_SPINLOCK.
# 
# ChangeSet
#   2005/03/14 21:28:26-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] superio: Use msleep* calls instead of direct schedule* calls.
#   
#   Use msleep* calls instead of direct schedule* calls.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/superio/scx.c
#   2005/03/02 09:59:36-08:00 johnpol@2ka.mipt.ru +5 -5
#   superio: Use msleep* calls instead of direct schedule* calls.
# 
# drivers/superio/sc.c
#   2005/03/02 09:59:36-08:00 johnpol@2ka.mipt.ru +10 -10
#   superio: Use msleep* calls instead of direct schedule* calls.
# 
# drivers/superio/pc8736x.c
#   2005/03/02 09:59:36-08:00 johnpol@2ka.mipt.ru +5 -5
#   superio: Use msleep* calls instead of direct schedule* calls.
# 
# ChangeSet
#   2005/03/14 21:27:55-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] superio: change scx200 module name to scx.
#   
#   Change scx200 module name to scx.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/superio/scx.h
#   2005/03/02 09:59:42-08:00 johnpol@2ka.mipt.ru +1 -1
#   superio: change scx200 module name to scx.
# 
# drivers/superio/scx.c
#   2005/03/02 09:59:42-08:00 johnpol@2ka.mipt.ru +2 -2
#   superio: change scx200 module name to scx.
# 
# drivers/superio/Makefile
#   2005/03/02 09:59:42-08:00 johnpol@2ka.mipt.ru +1 -1
#   superio: change scx200 module name to scx.
# 
# ChangeSet
#   2005/03/14 21:27:16-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] superio: remove unneded exports and make some functions static.
#   
#   Remove unneded exports and make some functions static.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/superio/sc_gpio.h
#   2005/03/02 09:59:50-08:00 johnpol@2ka.mipt.ru +0 -7
#   superio: remove unneded exports and make some functions static.
# 
# drivers/superio/sc_gpio.c
#   2005/03/02 09:59:50-08:00 johnpol@2ka.mipt.ru +16 -14
#   superio: remove unneded exports and make some functions static.
# 
# drivers/superio/sc_acb.c
#   2005/03/02 09:59:50-08:00 johnpol@2ka.mipt.ru +10 -15
#   superio: remove unneded exports and make some functions static.
# 
# ChangeSet
#   2005/03/14 21:26:44-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] Re: kobject_uevent.c moved to kernel connector.
#   
#   kobject_uevent.c change which allows to use new kernel connector
#   interface.  More details at
#   http://marc.theaimsgroup.com/?l=linux-kernel&m=110370721906005&w=2
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# lib/kobject_uevent.c
#   2005/03/02 10:00:13-08:00 johnpol@2ka.mipt.ru +66 -0
#   Re: kobject_uevent.c moved to kernel connector.
# 
# ChangeSet
#   2005/03/14 21:26:15-08:00 greg@kroah.com 
#   [PATCH] superio: fix up some sparse warnings in the code
#   
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# drivers/superio/scx200.c
#   2005/03/02 10:00:20-08:00 greg@kroah.com +5 -5
#   superio: fix up some sparse warnings in the code
# 
# drivers/superio/sc_gpio.c
#   2005/03/02 10:00:20-08:00 greg@kroah.com +1 -1
#   superio: fix up some sparse warnings in the code
# 
# drivers/superio/pc8736x.c
#   2005/03/02 10:00:20-08:00 greg@kroah.com +6 -6
#   superio: fix up some sparse warnings in the code
# 
# ChangeSet
#   2005/03/14 21:25:41-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] superio: add SuperIO subsystem.
#   
#   SuperIO subsystem is new interface for different chips
#   that implement various logical devices inside.
#   Many embedded boards use such chips like SC1100 Geode processor
#   and PC87366. The latter for example contains
#   GPIO, Access Bus, Watchdog timer, Game port, MIDI port,
#   Voltage level monitor and Temperature sensor.
#   
#   SuperIO subsystem currently supports GPIO and
#   Access Bus logical devices in PC8736x and SCx200/SC1100 chips.
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/sc_conn.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +50 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/scx200.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +28 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/scx200.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +413 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc_w1.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +107 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc_gpio.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +57 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc_gpio.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +310 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc_conn.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +124 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc_acb.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +45 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc_acb.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +163 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +134 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/sc.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +780 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/pin_test.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +93 -0
#   superio: add SuperIO subsystem.
# 
# include/linux/sc_conn.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/include/linux/sc_conn.h
# 
# include/linux/connector.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +4 -1
#   superio: add SuperIO subsystem.
# 
# drivers/superio/scx200.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/scx200.h
# 
# drivers/superio/scx200.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/scx200.c
# 
# drivers/superio/sc_w1.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc_w1.c
# 
# drivers/superio/sc_gpio.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc_gpio.h
# 
# drivers/superio/sc_gpio.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc_gpio.c
# 
# drivers/superio/sc_conn.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc_conn.c
# 
# drivers/superio/sc_acb.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc_acb.h
# 
# drivers/superio/sc_acb.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc_acb.c
# 
# drivers/superio/sc.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc.h
# 
# drivers/superio/sc.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/sc.c
# 
# drivers/superio/pin_test.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/pin_test.c
# 
# drivers/superio/pc8736x.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +39 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/pc8736x.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +209 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/chain.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +37 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/chain.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +52 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/Makefile
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +11 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/Kconfig
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +56 -0
#   superio: add SuperIO subsystem.
# 
# drivers/Makefile
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +1 -0
#   superio: add SuperIO subsystem.
# 
# drivers/Kconfig
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +2 -0
#   superio: add SuperIO subsystem.
# 
# drivers/superio/pc8736x.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/pc8736x.h
# 
# drivers/superio/pc8736x.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/pc8736x.c
# 
# drivers/superio/chain.h
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/chain.h
# 
# drivers/superio/chain.c
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/chain.c
# 
# drivers/superio/Makefile
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/Makefile
# 
# drivers/superio/Kconfig
#   2005/03/02 10:00:28-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/Kconfig
# 
# ChangeSet
#   2005/03/14 21:25:11-08:00 johnpol@2ka.mipt.ru 
#   [PATCH] Add Kernel conector subsystem
#   
#   Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
#   Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
# 
# include/linux/connector.h
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +147 -0
#   Add Kernel conector subsystem
# 
# drivers/connector/connector.c
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +509 -0
#   Add Kernel conector subsystem
# 
# drivers/connector/cn_queue.c
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +219 -0
#   Add Kernel conector subsystem
# 
# drivers/connector/Makefile
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +2 -0
#   Add Kernel conector subsystem
# 
# include/linux/connector.h
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/include/linux/connector.h
# 
# drivers/connector/connector.c
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/connector/connector.c
# 
# drivers/connector/cn_queue.c
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/connector/cn_queue.c
# 
# drivers/connector/Makefile
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/connector/Makefile
# 
# drivers/connector/Kconfig
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +13 -0
#   Add Kernel conector subsystem
# 
# drivers/Makefile
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +2 -0
#   Add Kernel conector subsystem
# 
# drivers/Kconfig
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +2 -0
#   Add Kernel conector subsystem
# 
# drivers/connector/Kconfig
#   2005/03/02 10:01:44-08:00 johnpol@2ka.mipt.ru +0 -0
#   BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/connector/Kconfig
# 
diff -Nru a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/connector/cn_test.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,203 @@
+/*
+ * 	cn_test.c
+ * 
+ * 2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+
+#include "connector.h"
+
+static struct cb_id cn_test_id = { 0x123, 0x456 };
+static char cn_test_name[] = "cn_test";
+static struct sock *nls;
+static struct timer_list cn_test_timer;
+
+void cn_test_callback(void *data)
+{
+	struct cn_msg *msg = (struct cn_msg *)data;
+
+	printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+	       __func__, jiffies, msg->id.idx, msg->id.val, 
+	       msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+static int cn_test_want_notify(void)
+{
+	struct cn_ctl_msg *ctl;
+	struct cn_notify_req *req;
+	struct cn_msg *msg = NULL;
+	int size, size0;
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	u32 group = 1;
+
+	size0 = sizeof(*msg) + sizeof(*ctl) + 3*sizeof(*req);
+	
+	size = NLMSG_SPACE(size0);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "Failed to allocate new skb with size=%u.\n", size);
+
+		return -ENOMEM;
+	}
+
+	nlh = NLMSG_PUT(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh));
+
+	msg = (struct cn_msg *)NLMSG_DATA(nlh);
+
+	memset(msg, 0, size0);
+
+	msg->id.idx 	= -1;
+	msg->id.val 	= -1;
+	msg->seq 	= 0x123;
+	msg->ack 	= 0x345;
+	msg->len 	= size0 - sizeof(*msg);
+
+	ctl = (struct cn_ctl_msg *)(msg + 1);
+
+	ctl->idx_notify_num 	= 1;
+	ctl->val_notify_num 	= 2;
+	ctl->group		= group;
+	ctl->len		= msg->len - sizeof(*ctl);
+
+	req = (struct cn_notify_req *)(ctl + 1);
+
+	/*
+	 * Idx.
+	 */
+	req->first = cn_test_id.idx;
+	req->range = 10;
+
+	/*
+	 * Val 0.
+	 */
+	req++;
+	req->first = cn_test_id.val;
+	req->range = 10;
+	
+	/*
+	 * Val 1.
+	 */
+	req++;
+	req->first = cn_test_id.val + 20;
+	req->range = 10;
+	
+	NETLINK_CB(skb).dst_groups = ctl->group;
+	//netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
+	netlink_unicast(nls, skb, 0, 0);
+
+	printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);
+		
+	return 0;
+
+nlmsg_failure:
+	printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
+	kfree_skb(skb);
+	return -EINVAL;
+}
+
+static u32 cn_test_timer_counter;
+static void cn_test_timer_func(unsigned long __data)
+{
+	struct cn_msg *m;
+	char data[32];
+
+	m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
+	if (m)
+	{
+		memset(m, 0, sizeof(*m) + sizeof(data));
+
+		memcpy(&m->id, &cn_test_id, sizeof(m->id));
+		m->seq = cn_test_timer_counter;
+		m->len = sizeof(data);
+
+		m->len = scnprintf(data, sizeof(data), "counter = %u", cn_test_timer_counter) + 1;
+
+		memcpy(m+1, data, m->len);
+		
+		cbus_insert(m);
+		//cn_netlink_send(m, 0);
+		kfree(m);
+	}
+
+	cn_test_timer_counter++;
+
+	mod_timer(&cn_test_timer, jiffies + HZ);
+}
+
+static int cn_test_init(void)
+{
+	int err;
+#if 0
+	nls = netlink_kernel_create(NETLINK_TAPBASE + 1, NULL);
+	if (!nls) {
+		printk(KERN_ERR "Failed to create new netlink socket(%u).\n", NETLINK_NFLOG);
+		return -EIO;
+	}
+
+	err = cn_test_want_notify();
+	if (err)
+		goto err_out;
+#endif
+	err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
+	if (err)
+		goto err_out;
+	cn_test_id.val++;
+	err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
+	if (err) {
+		cn_del_callback(&cn_test_id);
+		goto err_out;
+	}
+
+	init_timer(&cn_test_timer);
+	cn_test_timer.function = cn_test_timer_func;
+	cn_test_timer.expires = jiffies + HZ;
+	cn_test_timer.data = 0;
+	add_timer(&cn_test_timer);
+
+	return 0;
+
+err_out:
+	if (nls && nls->sk_socket)
+		sock_release(nls->sk_socket);
+
+	return err;
+}
+
+static void cn_test_fini(void)
+{
+	del_timer_sync(&cn_test_timer);
+	cn_del_callback(&cn_test_id);
+	cn_test_id.val--;
+	cn_del_callback(&cn_test_id);
+	if (nls && nls->sk_socket)
+		sock_release(nls->sk_socket);
+}
+
+module_init(cn_test_init);
+module_exit(cn_test_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Connector's test module");
diff -Nru a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/connector/connector.txt	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,154 @@
+/*****************************************/
+Kernel Connector.
+/*****************************************/
+
+Kernel connector - new netlink based userspace <-> kernel space easy to use communication module.
+
+Connector driver adds possibility to connect various agents using
+netlink based network.
+One must register callback and identifier. When driver receives
+special netlink message with appropriate identifier, appropriate
+callback will be called.
+
+From the userspace point of view it's quite straightforward:
+socket();
+bind();
+send();
+recv();
+
+But if kernelspace want to use full power of such connections, driver
+writer must create special sockets, must know about struct sk_buff
+handling...
+Connector allows any kernelspace agents to use netlink based
+networking for inter-process communication in a significantly easier
+way:
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+void cn_netlink_send(struct cn_msg *msg, u32 __groups);
+
+struct cb_id
+{
+	__u32			idx;
+	__u32			val;
+};
+
+idx and val are unique identifiers which must be registered in connector.h
+for in-kernel usage.
+void (*callback) (void *) - is a callback function which will be called
+when message with above idx.val will be received by connector core.
+Argument for that function must be dereferenced to struct cn_msg *.
+
+struct cn_msg
+{
+	struct cb_id 		id;
+
+	__u32			seq;
+	__u32			ack;
+
+	__u32			len;		/* Length of the following data */
+	__u8			data[0];
+};
+
+/*****************************************/
+Connector interfaces.
+/*****************************************/
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+Registers new callback with connector core.
+
+struct cb_id *id 		- unique connector's user identifier.
+			  	  It must be registered in connector.h for legal in-kernel users.
+char *name 			- connector's callback symbolic name.
+void (*callback) (void *)	- connector's callback.
+				  Argument must be dereferenced to struct cn_msg *.
+
+void cn_del_callback(struct cb_id *id);
+Unregisters new callback with connector core.
+
+struct cb_id *id 		- unique connector's user identifier.
+
+void cn_netlink_send(struct cn_msg *msg, u32 __groups);
+Sends message to the specified groups.
+It can be safely called from any context, but may silently
+fail under strong memory pressure.
+
+struct cn_msg *			- message header(with attached data).
+u32 __groups			- destination groups.
+				  If __groups is zero, then appropriate group will
+				  be searched through all registered connector users,
+				  and message will be delivered to the group which was
+				  created for user with the same ID as in msg.
+				  If __groups is not zero, then message will be delivered
+				  to the specified group.
+
+Note: When registering new callback user, connector core assigns netlink group
+to the user which is equal to it's id.idx.
+
+/*****************************************/
+Protocol description.
+/*****************************************/
+
+Current offers transport layer with fixed header.
+Recommended protocol which uses such header is following:
+
+msg->seq and msg->ack are used to determine message genealogy.
+When someone sends message it puts there locally unique sequence
+and random acknowledge numbers.
+Sequence number may be copied into nlmsghdr->nlmsg_seq too.
+
+Sequence number is incremented with each message to be sent.
+
+If we expect reply to our message, then sequence number in received
+message MUST be the same as in original message, and acknowledge
+number MUST be the same + 1.
+
+If we receive message and it's sequence number is not equal to one
+we are expecting, then it is new message.
+If we receive message and it's sequence number is the same as one we
+are expecting, but it's acknowledge is not equal acknowledge number
+in original message + 1, then it is new message.
+
+Obviously, protocol header contains above id.
+
+connector allows event notification in the following form:
+kernel driver or userspace process can ask connector to notify it
+when selected id's will be turned on or off(registered or unregistered
+it's callback). It is done by sending special command to connector
+driver(it also registers itself with id={-1, -1}).
+
+As example of usage Documentation/connector now contains cn_test.c - 
+testing module which uses connector to request notification
+and to send messages.
+
+
+/*****************************************/
+CBUS.
+/*****************************************/
+
+This message bus allows message passing between different agents
+using connector's infrastructure.
+It is extremely fast for insert operations so it can be used in performance
+critical paths in any context instead of direct connector's methods calls.
+
+CBUS uses per CPU variables and thus allows message reordering,
+caller must be prepared (and use CPU id in it's messages).
+
+Usage is very simple - just call cbus_insert(struct cn_msg *msg);
+It can fail, so caller must check return value - zero on success
+and negative error code otherwise.
+
+Benchmark with modified fork connector and fork bomb on 2-way system
+did not show any differences between vanilla 2.6.11 and CBUS.
+
+
+
+/*****************************************/
+Reliability.
+/*****************************************/
+Netlink itself is not reliable protocol, 
+that means that messages can be lost
+due to memory pressure or process' receiving
+queue overflowed, so caller is warned 
+must be prepared. That is why struct cn_msg
+[main connector's message header] contains 
+u32 seq and u32 ack fields.
diff -Nru a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-ali1535	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,42 @@
+Kernel driver i2c-ali1535
+
+Supported adapters:
+  * Acer Labs, Inc. ALI 1535 (south bridge)
+    Datasheet: Now under NDA
+	http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com>,
+	Dan Eaton <dan.eaton@rocketlogix.com>,
+	Stephen Rousset<stephen.rousset@rocketlogix.com>
+												
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1535 South Bridge.
+
+The M1535 is a South bridge for portable systems. It is very similar to the
+M15x3 South bridges also produced by Acer Labs Inc.  Some of the registers
+within the part have moved and some have been redefined slightly.
+Additionally, the sequencing of the SMBus transactions has been modified to
+be more consistent with the sequencing recommended by the manufacturer and
+observed through testing.  These changes are reflected in this driver and
+can be identified by comparing this driver to the i2c-ali15x3 driver. For
+an overview of these chips see http://www.acerlabs.com
+
+The SMB controller is part of the M7101 device, which is an ACPI-compliant
+Power Management Unit (PMU).
+
+The whole M7101 device has to be enabled for the SMB to work. You can't
+just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
+We make sure that the SMB is enabled. We leave the ACPI alone.
+
+
+Features
+--------
+
+This driver controls the SMB Host only. This driver does not use
+interrupts.
diff -Nru a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-ali1563	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,27 @@
+Kernel driver i2c-ali1563
+
+Supported adapters:
+  * Acer Labs, Inc. ALI 1563 (south bridge)
+    Datasheet: Now under NDA
+	http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Author: Patrick Mochel <mochel@digitalimplant.org>
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1563 South Bridge.
+
+For an overview of these chips see http://www.acerlabs.com
+
+The M1563 southbridge is deceptively similar to the M1533, with a few
+notable exceptions. One of those happens to be the fact they upgraded the
+i2c core to be SMBus 2.0 compliant, and happens to be almost identical to
+the i2c controller found in the Intel 801 south bridges. 
+
+Features
+--------
+
+This driver controls the SMB Host only. This driver does not use
+interrupts.
diff -Nru a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-ali15x3	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,112 @@
+Kernel driver i2c-ali15x3
+
+Supported adapters:
+  * Acer Labs, Inc. ALI 1533 and 1543C (south bridge)
+    Datasheet: Now under NDA
+	http://www.ali.com.tw/eng/support/datasheet_request.php
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>, 
+	Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Module Parameters
+-----------------
+
+* force_addr: int
+  Initialize the base address of the i2c controller
+
+
+Notes
+-----
+
+The force_addr parameter is useful for boards that don't set the address in
+the BIOS. Does not do a PCI force; the device must still be present in
+lspci. Don't use this unless the driver complains that the base address is
+not set.
+
+Example: 'modprobe i2c-ali15x3 force_addr=0xe800'
+
+SMBus periodically hangs on ASUS P5A motherboards and can only be cleared
+by a power cycle. Cause unknown (see Issues below).
+
+
+Description
+-----------
+
+This is the driver for the SMB Host controller on Acer Labs Inc. (ALI)
+M1541 and M1543C South Bridges.
+
+The M1543C is a South bridge for desktop systems.
+The M1541 is a South bridge for portable systems.
+They are part of the following ALI chipsets:
+   
+ * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and 
+ 		100MHz CPU Front Side bus
+ * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz 
+ 		CPU Front Side bus
+   Some Aladdin V motherboards:
+	Asus P5A
+	Atrend ATC-5220
+	BCM/GVC VP1541
+	Biostar M5ALA
+	Gigabyte GA-5AX (** Generally doesn't work because the BIOS doesn't
+                            enable the 7101 device! **)
+	Iwill XA100 Plus
+	Micronics C200
+	Microstar (MSI) MS-5169
+
+  * "Aladdin IV" includes the M1541 Socket 7 North bridge
+   		with host bus up to 83.3 MHz.
+
+For an overview of these chips see http://www.acerlabs.com. At this time the
+full data sheets on the web site are password protected, however if you
+contact the ALI office in San Jose they may give you the password.
+
+The M1533/M1543C devices appear as FOUR separate devices on the PCI bus. An
+output of lspci will show something similar to the following:
+
+  00:02.0 USB Controller: Acer Laboratories Inc. M5237 (rev 03)
+  00:03.0 Bridge: Acer Laboratories Inc. M7101      <= THIS IS THE ONE WE NEED
+  00:07.0 ISA bridge: Acer Laboratories Inc. M1533 (rev c3)
+  00:0f.0 IDE interface: Acer Laboratories Inc. M5229 (rev c1)
+
+** IMPORTANT **
+** If you have a M1533 or M1543C on the board and you get
+** "ali15x3: Error: Can't detect ali15x3!"
+** then run lspci.
+** If you see the 1533 and 5229 devices but NOT the 7101 device,
+** then you must enable ACPI, the PMU, SMB, or something similar
+** in the BIOS. 
+** The driver won't work if it can't find the M7101 device.
+
+The SMB controller is part of the M7101 device, which is an ACPI-compliant
+Power Management Unit (PMU).
+
+The whole M7101 device has to be enabled for the SMB to work. You can't
+just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
+We make sure that the SMB is enabled. We leave the ACPI alone.
+
+Features 
+-------- 
+
+This driver controls the SMB Host only. The SMB Slave
+controller on the M15X3 is not enabled. This driver does not use
+interrupts.
+
+
+Issues
+------
+
+This driver requests the I/O space for only the SMB
+registers. It doesn't use the ACPI region.
+
+On the ASUS P5A motherboard, there are several reports that
+the SMBus will hang and this can only be resolved by
+powering off the computer. It appears to be worse when the board
+gets hot, for example under heavy CPU load, or in the summer.
+There may be electrical problems on this board.
+On the P5A, the W83781D sensor chip is on both the ISA and
+SMBus. Therefore the SMBus hangs can generally be avoided
+by accessing the W83781D on the ISA bus only.
+
diff -Nru a/Documentation/i2c/busses/i2c-amd756 b/Documentation/i2c/busses/i2c-amd756
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-amd756	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,25 @@
+Kernel driver i2c-amd756
+
+Supported adapters:
+  * AMD 756
+  * AMD 766
+  * AMD 768
+  * AMD 8111
+    Datasheets: Publicly available on AMD website
+
+  * nVidia nForce
+    Datasheet: Unavailable
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>,
+	Philip Edelbrock <phil@netroedge.com> 
+
+Description
+-----------
+
+This driver supports the AMD 756, 766, 768 and 8111 Peripheral Bus
+Controllers, and the nVidia nForce.
+
+Note that for the 8111, there are two SMBus adapters. The SMBus 1.0 adapter
+is supported by this driver, and the SMBus 2.0 adapter is supported by the
+i2c-amd8111 driver.
diff -Nru a/Documentation/i2c/busses/i2c-amd8111 b/Documentation/i2c/busses/i2c-amd8111
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-amd8111	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,41 @@
+Kernel driver i2c-adm8111
+
+Supported adapters:
+    * AMD-8111 SMBus 2.0 PCI interface
+
+Datasheets:
+	AMD datasheet not yet available, but almost everything can be found
+	in publically available ACPI 2.0 specification, which the adapter 
+	follows.
+
+Author: Vojtech Pavlik <vojtech@suse.cz>
+
+Description
+-----------
+
+If you see something like this:
+
+00:07.2 SMBus: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0 (rev 02)
+        Subsystem: Advanced Micro Devices [AMD] AMD-8111 SMBus 2.0
+        Flags: medium devsel, IRQ 19
+        I/O ports at d400 [size=32]
+
+in your 'lspci -v', then this driver is for your chipset.
+
+Process Call Support
+--------------------
+
+Supported.
+
+SMBus 2.0 Support
+-----------------
+
+Supported. Both PEC and block process call support is implemented. Slave
+mode or host notification are not yet implemented.
+
+Notes
+-----
+
+Note that for the 8111, there are two SMBus adapters. The SMBus 2.0 adapter
+is supported by this driver, and the SMBus 1.0 adapter is supported by the
+i2c-amd756 driver.
diff -Nru a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-i801	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,80 @@
+Kernel driver i2c-i801
+
+Supported adapters:
+  * Intel 82801AA and 82801AB (ICH and ICH0 - part of the
+    '810' and '810E' chipsets)
+  * Intel 82801BA (ICH2 - part of the '815E' chipset)
+  * Intel 82801CA/CAM (ICH3)
+  * Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported)
+  * Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported)
+  * Intel 6300ESB
+  * Intel 82801FB/FR/FW/FRW (ICH6)
+  * Intel ICH7
+    Datasheets: Publicly available at the Intel website
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>, 
+	Mark Studebaker <mdsxyz123@yahoo.com>
+
+
+Module Parameters
+-----------------
+
+* force_addr: int
+  Forcibly enable the ICH at the given address. EXTREMELY DANGEROUS!
+
+
+Description
+-----------
+
+The ICH (properly known as the 82801AA), ICH0 (82801AB), ICH2 (82801BA),
+ICH3 (82801CA/CAM) and later devices are Intel chips that are a part of
+Intel's '810' chipset for Celeron-based PCs, '810E' chipset for
+Pentium-based PCs, '815E' chipset, and others.
+
+The ICH chips contain at least SEVEN separate PCI functions in TWO logical
+PCI devices. An output of lspci will show something similar to the
+following:
+
+  00:1e.0 PCI bridge: Intel Corporation: Unknown device 2418 (rev 01)
+  00:1f.0 ISA bridge: Intel Corporation: Unknown device 2410 (rev 01)
+  00:1f.1 IDE interface: Intel Corporation: Unknown device 2411 (rev 01)
+  00:1f.2 USB Controller: Intel Corporation: Unknown device 2412 (rev 01)
+  00:1f.3 Unknown class [0c05]: Intel Corporation: Unknown device 2413 (rev 01)
+
+The SMBus controller is function 3 in device 1f. Class 0c05 is SMBus Serial
+Controller.
+
+If you do NOT see the 24x3 device at function 3, and you can't figure out
+any way in the BIOS to enable it,
+
+The ICH chips are quite similar to Intel's PIIX4 chip, at least in the
+SMBus controller.
+
+See the file i2c-piix4 for some additional information.
+
+
+Process Call Support
+--------------------
+
+Not supported.
+
+
+I2C Block Read Support
+----------------------
+
+Not supported at the moment.
+
+
+SMBus 2.0 Support
+-----------------
+
+The 82801DB (ICH4) and later chips support several SMBus 2.0 features.
+
+**********************
+The lm_sensors project gratefully acknowledges the support of Texas
+Instruments in the initial development of this driver.
+
+The lm_sensors project gratefully acknowledges the support of Intel in the
+development of SMBus 2.0 / ICH4 features of this driver.
diff -Nru a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-i810	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,46 @@
+Kernel driver i2c-i810
+
+Supported adapters:
+  * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH)
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+	Ralph Metzler <rjkm@thp.uni-koeln.de>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Main contact: Mark Studebaker <mdsxyz123@yahoo.com>
+
+Description 
+----------- 
+
+WARNING: If you have an '810' or '815' motherboard, your standard I2C
+temperature sensors are most likely on the 801's I2C bus. You want the
+i2c-i801 driver for those, not this driver.
+
+Now for the i2c-i810...
+
+The GMCH chip contains two I2C interfaces.
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org .
+
+The second interface is a general-purpose I2C bus. It may be connected to a
+TV-out chip such as the BT869 or possibly to a digital flat-panel display.
+
+Features
+-------- 
+
+Both busses use the i2c-algo-bit driver for 'bit banging'
+and support for specific transactions is provided by i2c-algo-bit.
+
+Issues
+------
+
+If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1),
+the test may fail; if so, the i2c-i810 driver won't be inserted. However,
+we think this has been fixed.
diff -Nru a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-nforce2	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,41 @@
+Kernel driver i2c-nforce2
+
+Supported adapters:
+  * nForce2 MCP                10de:0064 
+  * nForce2 Ultra 400 MCP      10de:0084 
+  * nForce3 Pro150 MCP         10de:00D4 
+  * nForce3 250Gb MCP          10de:00E4 
+  * nForce4 MCP	       	       10de:0052
+
+Datasheet: not publically available, but seems to be similar to the
+           AMD-8111 SMBus 2.0 adapter.
+
+Authors:
+	Hans-Frieder Vogt <hfvogt@arcor.de>, 
+	Thomas Leibold <thomas@plx.com>, 
+        Patrick Dreker <patrick@dreker.de>
+	
+Description
+-----------
+
+i2c-nforce2 is a driver for the SMBuses included in the nVidia nForce2 MCP.
+
+If your 'lspci -v' listing shows something like the following,
+
+00:01.1 SMBus: nVidia Corporation: Unknown device 0064 (rev a2)
+        Subsystem: Asustek Computer, Inc.: Unknown device 0c11
+        Flags: 66Mhz, fast devsel, IRQ 5
+        I/O ports at c000 [size=32]
+        Capabilities: <available only to root>
+
+then this driver should support the SMBuses of your motherboard.
+
+
+Notes
+-----
+
+The SMBus adapter in the nForce2 chipset seems to be very similar to the
+SMBus 2.0 adapter in the AMD-8111 southbridge. However, I could only get
+the driver to work with direct I/O access, which is different to the EC
+interface of the AMD-8111. Tested on Asus A7N8X. The ACPI DSDT table of the
+Asus A7N8X lists two SMBuses, both of which are supported by this driver.
diff -Nru a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-parport	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,154 @@
+Kernel driver i2c-parport
+
+Author: Jean Delvare <khali@linux-fr.org> 
+
+This is a unified driver for several i2c-over-parallel-port adapters,
+such as the ones made by Philips, Velleman or ELV. This driver is
+meant as a replacement for the older, individual drivers:
+ * i2c-philips-par
+ * i2c-elv
+ * i2c-velleman
+ * video/i2c-parport (NOT the same as this one, dedicated to home brew
+                      teletext adapters)
+
+It currently supports the following devices:
+ * Philips adapter
+ * home brew teletext adapter
+ * Velleman K8000 adapter
+ * ELV adapter
+ * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032)
+
+These devices use different pinout configurations, so you have to tell
+the driver what you have, using the type module parameter. There is no
+way to autodetect the devices. Support for different pinout configurations
+can be easily added when needed.
+
+
+Building your own adapter
+-------------------------
+
+If you want to build you own i2c-over-parallel-port adapter, here is
+a sample electronics schema (credits go to Sylvain Munaut):
+
+Device                                                      PC
+Side          ___________________Vdd (+)                    Side
+               |    |         |
+              ---  ---       ---
+              | |  | |       | |
+              |R|  |R|       |R|
+              | |  | |       | |
+              ---  ---       ---
+               |    |         |
+               |    |    /|   |
+SCL  ----------x--------o |-----------x-------------------  pin 2
+                    |    \|   |       |
+                    |         |       |
+                    |   |\    |       |
+SDA  ----------x----x---| o---x---------------------------  pin 13
+               |        |/            |
+               |                      |
+               |         /|           |
+               ---------o |----------------x--------------  pin 3
+                         \|           |    |
+                                      |    |
+                                     ---  ---
+                                     | |  | |
+                                     |R|  |R|
+                                     | |  | |
+                                     ---  ---
+                                      |    | 
+                                     ###  ###
+                                     GND  GND
+        
+Remarks:
+ - This is the exact pinout and electronics used on the Analog Devices
+   evaluation boards.
+                   /|
+ - All inverters -o |- must be 74HC05, they must be open collector output.
+                   \|
+ - All resitors are 10k.
+ - Pins 18-25 of the parallel port connected to GND.
+ - Pins 4-9 (D2-D7) could be used as VDD is the driver drives them high.
+   The ADM1032 evaluation board uses D4-D7. Beware that the amount of
+   current you can draw from the parallel port is limited. Also note that
+   all connected lines MUST BE driven at the same state, else you'll short
+   circuit the output buffers! So plugging the I2C adapter after loading
+   the i2c-parport module might be a good safety since data line state
+   prior to init may be unknown. 
+ - This is 5V!
+ - Obviously you cannot read SCL (so it's not really standard-compliant).
+   Pretty easy to add, just copy the SDA part and use another input pin.
+   That would give (ELV compatible pinout):
+
+
+Device                                                      PC
+Side          ______________________________Vdd (+)         Side
+               |    |            |    |
+              ---  ---          ---  ---
+              | |  | |          | |  | |
+              |R|  |R|          |R|  |R|
+              | |  | |          | |  | |
+              ---  ---          ---  ---
+               |    |            |    |
+               |    |      |\    |    |
+SCL  ----------x--------x--| o---x------------------------  pin 15
+                    |   |  |/         | 
+                    |   |             |
+                    |   |   /|        |
+                    |   ---o |-------------x--------------  pin 2
+                    |       \|        |    |
+                    |                 |    |
+                    |                 |    |
+                    |      |\         |    |
+SDA  ---------------x---x--| o--------x-------------------  pin 10
+                        |  |/              |
+                        |                  |
+                        |   /|             |
+                        ---o |------------------x---------  pin 3
+                            \|             |    |
+                                           |    |
+                                          ---  ---
+                                          | |  | |
+                                          |R|  |R|
+                                          | |  | |
+                                          ---  ---
+                                           |    | 
+                                          ###  ###
+                                          GND  GND
+
+
+If possible, you should use the same pinout configuration as existing
+adapters do, so you won't even have to change the code.
+
+
+Similar (but different) drivers
+-------------------------------
+
+This driver is NOT the same as the i2c-pport driver found in the i2c
+package. The i2c-pport driver makes use of modern parallel port features so
+that you don't need additional electronics. It has other restrictions
+however, and was not ported to Linux 2.6 (yet).
+
+This driver is also NOT the same as the i2c-pcf-epp driver found in the
+lm_sensors package. The i2c-pcf-epp driver doesn't use the parallel port as
+an I2C bus directly. Instead, it uses it to control an external I2C bus
+master. That driver was not ported to Linux 2.6 (yet) either.
+
+
+Legacy documentation for Velleman adapter
+-----------------------------------------
+
+Useful links:
+Velleman                http://www.velleman.be/
+Velleman K8000 Howto    http://howto.htlw16.ac.at/k8000-howto.html
+
+The project has lead to new libs for the Velleman K8000 and K8005:
+  LIBK8000 v1.99.1 and LIBK8005 v0.21
+With these libs, you can control the K8000 interface card and the K8005
+stepper motor card with the simple commands which are in the original
+Velleman software, like SetIOchannel, ReadADchannel, SendStepCCWFull and
+many more, using /dev/velleman.
+  http://home.wanadoo.nl/hihihi/libk8000.htm
+  http://home.wanadoo.nl/hihihi/libk8005.htm
+  http://struyve.mine.nu:8080/index.php?block=k8000
+  http://sourceforge.net/projects/libk8005/
diff -Nru a/Documentation/i2c/busses/i2c-parport-light b/Documentation/i2c/busses/i2c-parport-light
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-parport-light	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,11 @@
+Kernel driver i2c-parport-light
+
+Author: Jean Delvare <khali@linux-fr.org> 
+
+This driver is a light version of i2c-parport. It doesn't depend        
+on the parport driver, and uses direct I/O access instead. This might be
+prefered on embedded systems where wasting memory for the clean but heavy
+parport handling is not an option. The drawback is a reduced portability
+and the impossibility to daisy-chain other parallel port devices.                 
+  
+Please see i2c-parport for documentation.
diff -Nru a/Documentation/i2c/busses/i2c-pca-isa b/Documentation/i2c/busses/i2c-pca-isa
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-pca-isa	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,23 @@
+Kernel driver i2c-pca-isa
+
+Supported adapters:
+This driver supports ISA boards using the Philips PCA 9564 
+Parallel bus to I2C bus controller 
+
+Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems 
+
+Module Parameters
+-----------------
+
+* base int
+ I/O base address
+* irq int
+ IRQ interrupt 
+* clock int 
+ Clock rate as described in table 1 of PCA9564 datasheet
+
+Description
+-----------
+
+This driver supports ISA boards using the Philips PCA 9564 
+Parallel bus to I2C bus controller 
diff -Nru a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-piix4	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,72 @@
+Kernel driver i2c-piix4
+
+Supported adapters:
+  * Intel 82371AB PIIX4 and PIIX4E
+  * Intel 82443MX (440MX)
+    Datasheet: Publicly available at the Intel website
+  * ServerWorks OSB4, CSB5 and CSB6 southbridges
+    Datasheet: Only available via NDA from ServerWorks
+  * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
+    Datasheet: Publicly available at the SMSC website http://www.smsc.com
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>
+	Philip Edelbrock <phil@netroedge.com>
+
+
+Module Parameters
+-----------------
+
+* force: int
+  Forcibly enable the PIIX4. DANGEROUS!
+* force_addr: int
+  Forcibly enable the PIIX4 at the given address. EXTREMELY DANGEROUS!
+* fix_hstcfg: int
+  Fix config register. Needed on some boards (Force CPCI735).
+
+
+Description
+-----------
+
+The PIIX4 (properly known as the 82371AB) is an Intel chip with a lot of
+functionality. Among other things, it implements the PCI bus. One of its
+minor functions is implementing a System Management Bus. This is a true 
+SMBus - you can not access it on I2C levels. The good news is that it
+natively understands SMBus commands and you do not have to worry about
+timing problems. The bad news is that non-SMBus devices connected to it can
+confuse it mightily. Yes, this is known to happen...
+
+Do 'lspci -v' and see whether it contains an entry like this:
+
+0000:00:02.3 Bridge: Intel Corp. 82371AB/EB/MB PIIX4 ACPI (rev 02)
+	     Flags: medium devsel, IRQ 9
+
+Bus and device numbers may differ, but the function number must be
+identical (like many PCI devices, the PIIX4 incorporates a number of
+different 'functions', which can be considered as separate devices). If you
+find such an entry, you have a PIIX4 SMBus controller.
+
+On some computers (most notably, some Dells), the SMBus is disabled by
+default. If you use the insmod parameter 'force=1', the kernel module will
+try to enable it. THIS IS VERY DANGEROUS! If the BIOS did not set up a
+correct address for this module, you could get in big trouble (read:
+crashes, data corruption, etc.). Try this only as a last resort (try BIOS
+updates first, for example), and backup first! An even more dangerous
+option is 'force_addr=<IOPORT>'. This will not only enable the PIIX4 like
+'force' foes, but it will also set a new base I/O port address. The SMBus
+parts of the PIIX4 needs a range of 8 of these addresses to function
+correctly. If these addresses are already reserved by some other device,
+you will get into big trouble! DON'T USE THIS IF YOU ARE NOT VERY SURE
+ABOUT WHAT YOU ARE DOING!
+
+The PIIX4E is just an new version of the PIIX4; it is supported as well.
+The PIIX/PIIX3 does not implement an SMBus or I2C bus, so you can't use
+this driver on those mainboards.
+
+The ServerWorks Southbridges, the Intel 440MX, and the Victory766 are
+identical to the PIIX4 in I2C/SMBus support.
+
+A few OSB4 southbridges are known to be misconfigured by the BIOS. In this
+case, you have you use the fix_hstcfg module parameter. Do not use it
+unless you know you have to, because in some cases it also breaks
+configuration on southbridges that don't need it.
diff -Nru a/Documentation/i2c/busses/i2c-prosavage b/Documentation/i2c/busses/i2c-prosavage
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-prosavage	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,23 @@
+Kernel driver i2c-prosavage
+
+Supported adapters:
+	
+	S3/VIA KM266/VT8375 aka ProSavage8 
+	S3/VIA KM133/VT8365 aka Savage4 
+
+Author: Henk Vergonet <henk@god.dyndns.org>
+
+Description
+-----------
+
+The Savage4 chips contain two I2C interfaces (aka a I2C 'master' or
+'host'). 
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org . The second interface is a general-purpose I2C bus.
+
+Usefull for gaining access to the TV Encoder chips.
+
diff -Nru a/Documentation/i2c/busses/i2c-savage4 b/Documentation/i2c/busses/i2c-savage4
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-savage4	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,26 @@
+Kernel driver i2c-savage4
+
+Supported adapters:
+  * Savage4
+  * Savage2000
+
+Authors: 
+	Alexander Wold <awold@bigfoot.com>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com> 
+
+Description
+-----------
+
+The Savage4 chips contain two I2C interfaces (aka a I2C 'master'
+or 'host'). 
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org . The DDC bus is not yet supported because its register
+is not directly memory-mapped.
+
+The second interface is a general-purpose I2C bus. This is the only
+interface supported by the driver at the moment.
+
diff -Nru a/Documentation/i2c/busses/i2c-sis5595 b/Documentation/i2c/busses/i2c-sis5595
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-sis5595	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,59 @@
+Kernel driver i2c-sis5595
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>,
+        Mark D. Studebaker <mdsxyz123@yahoo.com>,
+	Philip Edelbrock <phil@netroedge.com> 
+
+Supported adapters:
+  * Silicon Integrated Systems Corp. SiS5595 Southbridge
+    Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
+
+Note: all have mfr. ID 0x1039. 
+
+   SUPPORTED            PCI ID           
+        5595            0008 
+ 
+   Note: these chips contain a 0008 device which is incompatible with the 
+         5595. We recognize these by the presence of the listed 
+         "blacklist" PCI ID and refuse to load. 
+ 
+   NOT SUPPORTED        PCI ID          BLACKLIST PCI ID         
+         540            0008            0540 
+         550            0008            0550 
+        5513            0008            5511 
+        5581            0008            5597 
+        5582            0008            5597 
+        5597            0008            5597 
+        5598            0008            5597/5598 
+         630            0008            0630 
+         645            0008            0645 
+         646            0008            0646 
+         648            0008            0648 
+         650            0008            0650 
+         651            0008            0651 
+         730            0008            0730 
+         735            0008            0735 
+         745            0008            0745 
+         746            0008            0746 
+
+Module Parameters
+-----------------
+
+* force_addr=0xaddr	Set the I/O base address. Useful for boards
+			that don't set the address in the BIOS. Does not do a
+			PCI force; the device must still be present in lspci.
+			Don't use this unless the driver complains that the
+			base address is not set.
+
+Description
+-----------
+
+i2c-sis5595 is a true SMBus host driver for motherboards with the SiS5595
+southbridges.
+
+WARNING: If you are trying to access the integrated sensors on the SiS5595
+chip, you want the sis5595 driver for those, not this driver. This driver
+is a BUS driver, not a CHIP driver. A BUS driver is used by other CHIP
+drivers to access chips on the bus.
+
diff -Nru a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-sis630	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,49 @@
+Kernel driver i2c-sis630
+
+Supported adapters:
+  * Silicon Integrated Systems Corp (SiS)
+	630 chipset (Datasheet: available at http://amalysh.bei.t-online.de/docs/SIS/)
+	730 chipset
+  * Possible other SiS chipsets ?
+
+Author: Alexander Malysh <amalysh@web.de>
+
+Module Parameters
+-----------------
+
+* force = [1|0] Forcibly enable the SIS630. DANGEROUS!
+		This can be interesting for chipsets not named
+		above to check if it works for you chipset, but DANGEROUS!
+		
+* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, 
+			what your BIOS use). DANGEROUS! This should be a bit 
+			faster, but freeze some systems (i.e. my Laptop).
+
+
+Description
+-----------
+
+This SMBus only driver is known to work on motherboards with the above
+named chipsets.
+
+If you see something like this:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31)
+00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+
+or like this:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02)
+00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+
+in your 'lspci' output , then this driver is for your chipset.
+
+Thank You
+---------
+Philip Edelbrock <phil@netroedge.com>
+- testing SiS730 support
+Mark M. Hoffman <mhoffman@lightlink.com>
+- bug fixes
+ 
+To anyone else which I forgot here ;), thanks!
+
diff -Nru a/Documentation/i2c/busses/i2c-sis69x b/Documentation/i2c/busses/i2c-sis69x
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-sis69x	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,73 @@
+Kernel driver i2c-sis96x
+
+Replaces 2.4.x i2c-sis645
+
+Supported adapters:
+  * Silicon Integrated Systems Corp (SiS)
+    Any combination of these host bridges:
+	645, 645DX (aka 646), 648, 650, 651, 655, 735, 745, 746
+    and these south bridges:
+    	961, 962, 963(L) 
+
+Author: Mark M. Hoffman <mhoffman@lightlink.com>
+
+Description
+-----------
+
+This SMBus only driver is known to work on motherboards with the above
+named chipset combinations. The driver was developed without benefit of a
+proper datasheet from SiS. The SMBus registers are assumed compatible with
+those of the SiS630, although they are located in a completely different
+place. Thanks to Alexander Malysh <amalysh@web.de> for providing the
+SiS630 datasheet (and  driver).
+
+The command "lspci" as root should produce something like these lines:
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645
+00:02.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513
+00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016
+
+or perhaps this...
+
+00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 
+00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961
+00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016
+
+(kernel versions later than 2.4.18 may fill in the "Unknown"s)
+
+If you cant see it please look on quirk_sis_96x_smbus
+(drivers/pci/quirks.c) (also if southbridge detection fails)
+
+I suspect that this driver could be made to work for the following SiS
+chipsets as well: 635, and 635T. If anyone owns a board with those chips
+AND is willing to risk crashing & burning an otherwise well-behaved kernel
+in the name of progress... please contact me at <mhoffman@lightlink.com> or
+via the project's mailing list: <sensors@stimpy.netroedge.com>.  Please
+send bug reports and/or success stories as well.
+
+
+TO DOs
+------
+
+* The driver does not support SMBus block reads/writes; I may add them if a
+scenario is found where they're needed.
+
+
+Thank You
+---------
+
+Mark D. Studebaker <mdsxyz123@yahoo.com>
+ - design hints and bug fixes
+Alexander Maylsh <amalysh@web.de>
+ - ditto, plus an important datasheet... almost the one I really wanted
+Hans-Günter Lütke Uphues <hg_lu@t-online.de>
+ - patch for SiS735
+Robert Zwerus <arzie@dds.nl>
+ - testing for SiS645DX
+Kianusch Sayah Karadji <kianusch@sk-tech.net>
+ - patch for SiS645DX/962
+Ken Healy
+ - patch for SiS655
+
+To anyone else who has written w/ feedback, thanks!
+
diff -Nru a/Documentation/i2c/busses/i2c-via b/Documentation/i2c/busses/i2c-via
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-via	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,34 @@
+Kernel driver i2c-via
+
+Supported adapters:
+  * VIA Technologies, InC. VT82C586B
+    Datasheet: Publicly available at the VIA website
+
+Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+Description
+-----------
+
+i2c-via is an i2c bus driver for motherboards with VIA chipset.
+
+The following VIA pci chipsets are supported:
+ - MVP3, VP3, VP2/97, VPX/97 
+ - others with South bridge VT82C586B
+
+Your lspci listing must show this :
+
+ Bridge: VIA Technologies, Inc. VT82C586B ACPI (rev 10)
+
+    Problems?
+ 
+ Q: You have VT82C586B on the motherboard, but not in the listing. 
+ 
+ A: Go to your BIOS setup, section PCI devices or similar.
+    Turn USB support on, and try again. 
+
+ Q: No error messages, but still i2c doesn't seem to work.
+
+ A: This can happen. This driver uses the pins VIA recommends in their
+    datasheets, but there are several ways the motherboard manufacturer
+    can actually wire the lines.
+
diff -Nru a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-viapro	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,47 @@
+Kernel driver i2c-viapro
+
+Supported adapters:
+  * VIA Technologies, Inc. VT82C596A/B
+    Datasheet: Sometimes available at the VIA website
+
+  * VIA Technologies, Inc. VT82C686A/B 
+    Datasheet: Sometimes available at the VIA website
+
+  * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237
+    Datasheet: available on request from Via
+
+Authors:
+	Frodo Looijaard <frodol@dds.nl>,  
+	Philip Edelbrock <phil@netroedge.com>, 
+	Kyösti Mälkki <kmalkki@cc.hut.fi>, 
+	Mark D. Studebaker <mdsxyz123@yahoo.com> 
+
+Module Parameters
+-----------------
+
+* force: int
+  Forcibly enable the SMBus controller. DANGEROUS!
+* force_addr: int
+  Forcibly enable the SMBus at the given address. EXTREMELY DANGEROUS!
+
+Description
+-----------
+
+i2c-viapro is a true SMBus host driver for motherboards with one of the
+supported VIA southbridges.
+
+Your lspci -n listing must show one of these :
+
+ device 1106:3050   (VT82C596 function 3)
+ device 1106:3051   (VT82C596 function 3)
+ device 1106:3057   (VT82C686 function 4)
+ device 1106:3074   (VT8233)
+ device 1106:3147   (VT8233A)
+ device 1106:8235   (VT8231)
+ devide 1106:3177   (VT8235)
+ devide 1106:3227   (VT8237)
+
+If none of these show up, you should look in the BIOS for settings like
+enable ACPI / SMBus or even USB.
+
+
diff -Nru a/Documentation/i2c/busses/i2c-voodoo3 b/Documentation/i2c/busses/i2c-voodoo3
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/i2c-voodoo3	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,62 @@
+Kernel driver i2c-voodoo3
+
+Supported adapters:
+  * 3dfx Voodoo3 based cards
+  * Voodoo Banshee based cards
+
+Authors: 
+	Frodo Looijaard <frodol@dds.nl>, 
+	Philip Edelbrock <phil@netroedge.com>, 
+	Ralph Metzler <rjkm@thp.uni-koeln.de>,
+	Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+Main contact: Philip Edelbrock <phil@netroedge.com>
+	
+The code is based upon Ralph's test code (he did the hard stuff ;')
+
+Description
+-----------
+
+The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' or
+'host'). 
+
+The first interface is used for DDC (Data Display Channel) which is a
+serial channel through the VGA monitor connector to a DDC-compliant
+monitor. This interface is defined by the Video Electronics Standards
+Association (VESA). The standards are available for purchase at
+http://www.vesa.org .
+
+The second interface is a general-purpose I2C bus. The intent by 3dfx was
+to allow manufacturers to add extra chips to the video card such as a
+TV-out chip such as the BT869 or possibly even I2C based temperature
+sensors like the ADM1021 or LM75.
+
+Stability
+---------
+
+Seems to be stable on the test machine, but needs more testing on other
+machines. Simultaneous accesses of the DDC and I2C busses may cause errors.
+
+Supported Devices
+-----------------
+
+Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP
+3000' which has a tv-out feature (s-video or composite).  According to the
+docs and discussions, this code should work for any Voodoo3 based cards as
+well as Voodoo Banshee based cards.  The DDC interface has been tested on a
+Voodoo Banshee card.
+	
+Issues
+------
+
+Probably many, but it seems to work OK on my system. :')
+
+
+External Device Connection
+--------------------------
+
+The digital video input jumpers give availability to the I2C bus. 
+Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are     
+the I2C clock and I2C data lines, respectively. +5V and GND are probably
+also easily available making the addition of extra I2C/SMBus devices easy
+to implement.
diff -Nru a/Documentation/i2c/busses/scx200_acb b/Documentation/i2c/busses/scx200_acb
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/i2c/busses/scx200_acb	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,14 @@
+Kernel driver scx200_acb
+
+Author: Christer Weinigel <wingel@nano-system.com>
+
+Module Parameters
+-----------------
+
+* base: int
+  Base addresses for the ACCESS.bus controllers
+
+Description
+-----------
+
+Enable the use of the ACCESS.bus controllers of a SCx200 processor.
diff -Nru a/Documentation/i2c/i2c-parport b/Documentation/i2c/i2c-parport
--- a/Documentation/i2c/i2c-parport	2005-03-30 17:24:44 -08:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,156 +0,0 @@
-==================
-i2c-parport driver
-==================
-
-2004-07-06, Jean Delvare
-
-This is a unified driver for several i2c-over-parallel-port adapters,
-such as the ones made by Philips, Velleman or ELV. This driver is
-meant as a replacement for the older, individual drivers:
- * i2c-philips-par
- * i2c-elv
- * i2c-velleman
- * video/i2c-parport (NOT the same as this one, dedicated to home brew
-                      teletext adapters)
-
-It currently supports the following devices:
- * Philips adapter
- * home brew teletext adapter
- * Velleman K8000 adapter
- * ELV adapter
- * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032)
-
-These devices use different pinout configurations, so you have to tell
-the driver what you have, using the type module parameter. There is no
-way to autodetect the devices. Support for different pinout configurations
-can be easily added when needed.
-
-
-Building your own adapter
--------------------------
-
-If you want to build you own i2c-over-parallel-port adapter, here is
-a sample electronics schema (credits go to Sylvain Munaut):
-
-Device                                                      PC
-Side          ___________________Vdd (+)                    Side
-               |    |         |
-              ---  ---       ---
-              | |  | |       | |
-              |R|  |R|       |R|
-              | |  | |       | |
-              ---  ---       ---
-               |    |         |
-               |    |    /|   |
-SCL  ----------x--------o |-----------x-------------------  pin 2
-                    |    \|   |       |
-                    |         |       |
-                    |   |\    |       |
-SDA  ----------x----x---| o---x---------------------------  pin 13
-               |        |/            |
-               |                      |
-               |         /|           |
-               ---------o |----------------x--------------  pin 3
-                         \|           |    |
-                                      |    |
-                                     ---  ---
-                                     | |  | |
-                                     |R|  |R|
-                                     | |  | |
-                                     ---  ---
-                                      |    | 
-                                     ###  ###
-                                     GND  GND
-        
-Remarks:
- - This is the exact pinout and electronics used on the Analog Devices
-   evaluation boards.
-                   /|
- - All inverters -o |- must be 74HC05, they must be open collector output.
-                   \|
- - All resitors are 10k.
- - Pins 18-25 of the parallel port connected to GND.
- - Pins 4-9 (D2-D7) could be used as VDD is the driver drives them high.
-   The ADM1032 evaluation board uses D4-D7. Beware that the amount of
-   current you can draw from the parallel port is limited. Also note that
-   all connected lines MUST BE driven at the same state, else you'll short
-   circuit the output buffers! So plugging the I2C adapter after loading
-   the i2c-parport module might be a good safety since data line state
-   prior to init may be unknown. 
- - This is 5V!
- - Obviously you cannot read SCL (so it's not really standard-compliant).
-   Pretty easy to add, just copy the SDA part and use another input pin.
-   That would give (ELV compatible pinout):
-
-
-Device                                                      PC
-Side          ______________________________Vdd (+)         Side
-               |    |            |    |
-              ---  ---          ---  ---
-              | |  | |          | |  | |
-              |R|  |R|          |R|  |R|
-              | |  | |          | |  | |
-              ---  ---          ---  ---
-               |    |            |    |
-               |    |      |\    |    |
-SCL  ----------x--------x--| o---x------------------------  pin 15
-                    |   |  |/         | 
-                    |   |             |
-                    |   |   /|        |
-                    |   ---o |-------------x--------------  pin 2
-                    |       \|        |    |
-                    |                 |    |
-                    |                 |    |
-                    |      |\         |    |
-SDA  ---------------x---x--| o--------x-------------------  pin 10
-                        |  |/              |
-                        |                  |
-                        |   /|             |
-                        ---o |------------------x---------  pin 3
-                            \|             |    |
-                                           |    |
-                                          ---  ---
-                                          | |  | |
-                                          |R|  |R|
-                                          | |  | |
-                                          ---  ---
-                                           |    | 
-                                          ###  ###
-                                          GND  GND
-
-
-If possible, you should use the same pinout configuration as existing
-adapters do, so you won't even have to change the code.
-
-
-Similar (but different) drivers
--------------------------------
-
-This driver is NOT the same as the i2c-pport driver found in the i2c package.
-The i2c-pport driver makes use of modern parallel port features so that
-you don't need additional electronics. It has other restrictions however, and
-was not ported to Linux 2.6 (yet).
-
-This driver is also NOT the same as the i2c-pcf-epp driver found in the
-lm_sensors package. The i2c-pcf-epp driver doesn't use the parallel port
-as an I2C bus directly. Instead, it uses it to control an external I2C bus
-master. That driver was not ported to Linux 2.6 (yet) either.
-
-
-Legacy documentation for Velleman adapter
------------------------------------------
-
-Useful links:
-Velleman                http://www.velleman.be/
-Velleman K8000 Howto    http://howto.htlw16.ac.at/k8000-howto.html
-
-The project has lead to new libs for the Velleman K8000 and K8005:
-  LIBK8000 v1.99.1 and LIBK8005 v0.21
-With these libs, you can control the K8000 interface card and the K8005
-stepper motor card with the simple commands which are in the original
-Velleman software, like SetIOchannel, ReadADchannel, SendStepCCWFull and
-many more, using /dev/velleman.
-  http://home.wanadoo.nl/hihihi/libk8000.htm
-  http://home.wanadoo.nl/hihihi/libk8005.htm
-  http://struyve.mine.nu:8080/index.php?block=k8000
-  http://sourceforge.net/projects/libk8005/
diff -Nru a/drivers/Kconfig b/drivers/Kconfig
--- a/drivers/Kconfig	2005-03-30 17:24:44 -08:00
+++ b/drivers/Kconfig	2005-03-30 17:24:44 -08:00
@@ -4,6 +4,8 @@
 
 source "drivers/base/Kconfig"
 
+source "drivers/connector/Kconfig"
+
 source "drivers/mtd/Kconfig"
 
 source "drivers/parport/Kconfig"
@@ -43,6 +45,8 @@
 source "drivers/i2c/Kconfig"
 
 source "drivers/w1/Kconfig"
+
+source "drivers/superio/Kconfig"
 
 source "drivers/misc/Kconfig"
 
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	2005-03-30 17:24:44 -08:00
+++ b/drivers/Makefile	2005-03-30 17:24:44 -08:00
@@ -17,6 +17,8 @@
 # default.
 obj-y				+= char/
 
+obj-$(CONFIG_CONNECTOR)	+= connector/
+
 # i810fb and intelfb depend on char/agp/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
@@ -52,6 +54,7 @@
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
+obj-$(CONFIG_SC_SUPERIO)	+= superio/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
 obj-$(CONFIG_BT)		+= bluetooth/
diff -Nru a/drivers/connector/Kconfig b/drivers/connector/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/connector/Kconfig	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,13 @@
+menu "Connector - unified userspace <-> kernelspace linker"
+
+config CONNECTOR
+	tristate "Connector - unified userspace <-> kernelspace linker"
+	depends on NET
+	---help---
+	  This is unified userspace <-> kernelspace connector working on top
+	  of the netlink socket protocol.
+
+	  Connector support can also be built as a module.  If so, the module
+	  will be called cn.ko.
+
+endmenu
diff -Nru a/drivers/connector/Makefile b/drivers/connector/Makefile
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/connector/Makefile	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CONNECTOR)		+= cn.o
+cn-objs		:= cn_queue.o connector.o
diff -Nru a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/connector/cn_queue.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,231 @@
+/*
+ * 	cn_queue.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/suspend.h>
+#include <linux/connector.h>
+#include <linux/delay.h>
+
+static void cn_queue_wrapper(void *data)
+{
+	struct cn_callback_entry *cbq = (struct cn_callback_entry *)data;
+
+	smp_mb__before_atomic_inc();
+	atomic_inc(&cbq->cb->refcnt);
+	smp_mb__after_atomic_inc();
+	cbq->cb->callback(cbq->cb->priv);
+	smp_mb__before_atomic_inc();
+	atomic_dec(&cbq->cb->refcnt);
+	smp_mb__after_atomic_inc();
+
+	cbq->destruct_data(cbq->ddata);
+}
+
+static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb)
+{
+	struct cn_callback_entry *cbq;
+
+	cbq = kmalloc(sizeof(*cbq), GFP_KERNEL);
+	if (!cbq) {
+		printk(KERN_ERR "Failed to create new callback queue.\n");
+		return NULL;
+	}
+
+	memset(cbq, 0, sizeof(*cbq));
+
+	cbq->cb = cb;
+
+	INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
+
+	return cbq;
+}
+
+static void cn_queue_free_callback(struct cn_callback_entry *cbq)
+{
+	cancel_delayed_work(&cbq->work);
+
+	while (atomic_read(&cbq->cb->refcnt)) {
+		printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+		       cbq->pdev->name, atomic_read(&cbq->cb->refcnt));
+
+		msleep_interruptible(1000);
+
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+
+		if (signal_pending(current))
+			flush_signals(current);
+	}
+
+	kfree(cbq);
+}
+
+int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
+{
+#if 0
+	printk(KERN_INFO "%s: comparing %04x.%04x and %04x.%04x\n",
+			__func__,
+			i1->idx, i1->val,
+			i2->idx, i2->val);
+#endif
+	return ((i1->idx == i2->idx) && (i1->val == i2->val));
+}
+
+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
+{
+	struct cn_callback_entry *cbq, *n, *__cbq;
+	int found = 0;
+
+	cbq = cn_queue_alloc_callback_entry(cb);
+	if (!cbq)
+		return -ENOMEM;
+
+	atomic_inc(&dev->refcnt);
+	smp_mb__after_atomic_inc();
+	cbq->pdev = dev;
+
+	spin_lock_bh(&dev->queue_lock);
+	list_for_each_entry_safe(__cbq, n, &dev->queue_list, callback_entry) {
+		if (cn_cb_equal(&__cbq->cb->id, &cb->id)) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		atomic_set(&cbq->cb->refcnt, 1);
+		list_add_tail(&cbq->callback_entry, &dev->queue_list);
+	}
+	spin_unlock_bh(&dev->queue_lock);
+
+	if (found) {
+		smp_mb__before_atomic_inc();
+		atomic_dec(&dev->refcnt);
+		smp_mb__after_atomic_inc();
+		atomic_set(&cbq->cb->refcnt, 0);
+		cn_queue_free_callback(cbq);
+		return -EINVAL;
+	}
+
+	cbq->nls = dev->nls;
+	cbq->seq = 0;
+	cbq->group = cbq->cb->id.idx;
+
+	return 0;
+}
+
+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
+{
+	struct cn_callback_entry *cbq = NULL, *n;
+	int found = 0;
+
+	spin_lock_bh(&dev->queue_lock);
+	list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) {
+		if (cn_cb_equal(&cbq->cb->id, &cb->id)) {
+			list_del(&cbq->callback_entry);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_bh(&dev->queue_lock);
+
+	if (found) {
+		smp_mb__before_atomic_inc();
+		atomic_dec(&cbq->cb->refcnt);
+		smp_mb__after_atomic_inc();
+		cn_queue_free_callback(cbq);
+		smp_mb__before_atomic_inc();
+		atomic_dec(&dev->refcnt);
+		smp_mb__after_atomic_inc();
+	}
+}
+
+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)
+{
+	struct cn_queue_dev *dev;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		printk(KERN_ERR "%s: Failed to allocte new struct cn_queue_dev.\n",
+		       name);
+		return NULL;
+	}
+
+	memset(dev, 0, sizeof(*dev));
+
+	snprintf(dev->name, sizeof(dev->name), "%s", name);
+
+	atomic_set(&dev->refcnt, 0);
+	INIT_LIST_HEAD(&dev->queue_list);
+	spin_lock_init(&dev->queue_lock);
+
+	dev->nls = nls;
+	dev->netlink_groups = 0;
+
+	dev->cn_queue = create_workqueue(dev->name);
+	if (!dev->cn_queue) {
+		printk(KERN_ERR "Failed to create %s queue.\n", dev->name);
+		kfree(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+
+void cn_queue_free_dev(struct cn_queue_dev *dev)
+{
+	struct cn_callback_entry *cbq, *n;
+
+	flush_workqueue(dev->cn_queue);
+	destroy_workqueue(dev->cn_queue);
+
+	spin_lock_bh(&dev->queue_lock);
+	list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) {
+		list_del(&cbq->callback_entry);
+		smp_mb__before_atomic_inc();
+		atomic_dec(&cbq->cb->refcnt);
+		smp_mb__after_atomic_inc();
+	}
+	spin_unlock_bh(&dev->queue_lock);
+
+	while (atomic_read(&dev->refcnt)) {
+		printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+		       dev->name, atomic_read(&dev->refcnt));
+
+		msleep_interruptible(1000);
+
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+
+		if (signal_pending(current))
+			flush_signals(current);
+	}
+
+	memset(dev, 0, sizeof(*dev));
+	kfree(dev);
+	dev = NULL;
+}
diff -Nru a/drivers/connector/connector.c b/drivers/connector/connector.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/connector/connector.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,520 @@
+/*
+ * 	connector.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/moduleparam.h>
+#include <linux/connector.h>
+
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
+
+static int unit = NETLINK_NFLOG;
+static u32 cn_idx = -1;
+static u32 cn_val = -1;
+
+module_param(unit, int, 0);
+module_param(cn_idx, uint, 0);
+module_param(cn_val, uint, 0);
+
+static DEFINE_SPINLOCK(notify_lock);
+static LIST_HEAD(notify_list);
+
+static struct cn_dev cdev;
+
+int cn_already_initialized = 0;
+
+/*
+ * msg->seq and msg->ack are used to determine message genealogy.
+ * When someone sends message it puts there locally unique sequence 
+ * and random acknowledge numbers.
+ * Sequence number may be copied into nlmsghdr->nlmsg_seq too.
+ *
+ * Sequence number is incremented with each message to be sent.
+ *
+ * If we expect reply to our message, 
+ * then sequence number in received message MUST be the same as in original message,
+ * and acknowledge number MUST be the same + 1.
+ *
+ * If we receive message and it's sequence number is not equal to one we are expecting, 
+ * then it is new message.
+ * If we receive message and it's sequence number is the same as one we are expecting,
+ * but it's acknowledge is not equal acknowledge number in original message + 1,
+ * then it is new message.
+ *
+ */
+void cn_netlink_send(struct cn_msg *msg, u32 __groups)
+{
+	struct cn_callback_entry *n, *__cbq;
+	unsigned int size;
+	struct sk_buff *skb, *uskb;
+	struct nlmsghdr *nlh;
+	struct cn_msg *data;
+	struct cn_dev *dev = &cdev;
+	u32 groups = 0;
+	int found = 0;
+
+	if (!__groups)
+	{
+		spin_lock_bh(&dev->cbdev->queue_lock);
+		list_for_each_entry_safe(__cbq, n, &dev->cbdev->queue_list, callback_entry) {
+			if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {
+				found = 1;
+				groups = __cbq->group;
+			}
+		}
+		spin_unlock_bh(&dev->cbdev->queue_lock);
+
+		if (!found) {
+			printk(KERN_ERR "Failed to find multicast netlink group for callback[0x%x.0x%x]. seq=%u\n",
+			       msg->id.idx, msg->id.val, msg->seq);
+			return;
+		}
+	}
+	else
+		groups = __groups;
+
+	size = NLMSG_SPACE(sizeof(*msg) + msg->len);
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "Failed to allocate new skb with size=%u.\n", size);
+		return;
+	}
+
+	nlh = NLMSG_PUT(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh));
+
+	data = (struct cn_msg *)NLMSG_DATA(nlh);
+
+	memcpy(data, msg, sizeof(*data) + msg->len);
+#if 0
+	printk("%s: len=%u, seq=%u, ack=%u, group=%u.\n",
+	       __func__, msg->len, msg->seq, msg->ack, groups);
+#endif
+	
+	NETLINK_CB(skb).dst_groups = groups;
+
+	uskb = skb_clone(skb, GFP_ATOMIC);
+	if (uskb) {
+		netlink_unicast(dev->nls, uskb, 0, 0);
+	}
+	
+	netlink_broadcast(dev->nls, skb, 0, groups, GFP_ATOMIC);
+
+	return;
+
+nlmsg_failure:
+	printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
+	kfree_skb(skb);
+	return;
+}
+
+static int cn_call_callback(struct cn_msg *msg, void (*destruct_data) (void *), void *data)
+{
+	struct cn_callback_entry *n, *__cbq;
+	struct cn_dev *dev = &cdev;
+	int found = 0;
+
+	spin_lock_bh(&dev->cbdev->queue_lock);
+	list_for_each_entry_safe(__cbq, n, &dev->cbdev->queue_list, callback_entry) {
+		if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {
+			__cbq->cb->priv = msg;
+
+			__cbq->ddata = data;
+			__cbq->destruct_data = destruct_data;
+
+			queue_work(dev->cbdev->cn_queue, &__cbq->work);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_bh(&dev->cbdev->queue_lock);
+
+	return found;
+}
+
+static int __cn_rx_skb(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	u32 pid, uid, seq, group;
+	struct cn_msg *msg;
+
+	pid = NETLINK_CREDS(skb)->pid;
+	uid = NETLINK_CREDS(skb)->uid;
+	seq = nlh->nlmsg_seq;
+	group = NETLINK_CB((skb)).groups;
+	msg = (struct cn_msg *)NLMSG_DATA(nlh);
+
+	if (NLMSG_SPACE(msg->len + sizeof(*msg)) != nlh->nlmsg_len) {
+		printk(KERN_ERR "skb does not have enough length: "
+				"requested msg->len=%u[%u], nlh->nlmsg_len=%u, skb->len=%u.\n",
+				msg->len, NLMSG_SPACE(msg->len + sizeof(*msg)),
+				nlh->nlmsg_len, skb->len);
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+#if 0
+	printk(KERN_INFO "pid=%u, uid=%u, seq=%u, group=%u.\n",
+	       pid, uid, seq, group);
+#endif
+	return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
+}
+
+static void cn_rx_skb(struct sk_buff *__skb)
+{
+	struct nlmsghdr *nlh;
+	u32 len;
+	int err;
+	struct sk_buff *skb;
+
+	skb = skb_get(__skb);
+	if (!skb) {
+		printk(KERN_ERR "Failed to reference an skb.\n");
+		kfree_skb(__skb);
+		return;
+	}
+#if 0
+	printk(KERN_INFO
+	       "skb: len=%u, data_len=%u, truesize=%u, proto=%u, cloned=%d, shared=%d.\n",
+	       skb->len, skb->data_len, skb->truesize, skb->protocol,
+	       skb_cloned(skb), skb_shared(skb));
+#endif
+	while (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *)skb->data;
+		if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
+		    skb->len < nlh->nlmsg_len ||
+		    nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {
+#if 0
+			printk(KERN_INFO "nlmsg_len=%u, sizeof(*nlh)=%u\n",
+			       nlh->nlmsg_len, sizeof(*nlh));
+#endif
+			kfree_skb(skb);
+			break;
+		}
+
+		len = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (len > skb->len)
+			len = skb->len;
+
+		err = __cn_rx_skb(skb, nlh);
+		if (err) {
+#if 0
+			if (err < 0 && (nlh->nlmsg_flags & NLM_F_ACK))
+				netlink_ack(skb, nlh, -err);
+#endif
+			break;
+		} else {
+#if 0
+			if (nlh->nlmsg_flags & NLM_F_ACK)
+				netlink_ack(skb, nlh, 0);
+#endif
+			break;
+		}
+		skb_pull(skb, len);
+	}
+			
+	kfree_skb(__skb);
+}
+
+static void cn_input(struct sock *sk, int len)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
+		cn_rx_skb(skb);
+}
+
+static void cn_notify(struct cb_id *id, u32 notify_event)
+{
+	struct cn_ctl_entry *ent;
+
+	spin_lock_bh(&notify_lock);
+	list_for_each_entry(ent, &notify_list, notify_entry) {
+		int i;
+		struct cn_notify_req *req;
+		struct cn_ctl_msg *ctl = ent->msg;
+		int a, b;
+
+		a = b = 0;
+		
+		req = (struct cn_notify_req *)ctl->data;
+		for (i=0; i<ctl->idx_notify_num; ++i, ++req) {
+			if (id->idx >= req->first && id->idx < req->first + req->range) {
+				a = 1;
+				break;
+			}
+		}
+		
+		for (i=0; i<ctl->val_notify_num; ++i, ++req) {
+			if (id->val >= req->first && id->val < req->first + req->range) {
+				b = 1;
+				break;
+			}
+		}
+
+		if (a && b) {
+			struct cn_msg m;
+			
+			printk(KERN_INFO "Notifying group %x with event %u about %x.%x.\n", 
+					ctl->group, notify_event, 
+					id->idx, id->val);
+
+			memset(&m, 0, sizeof(m));
+			m.ack = notify_event;
+
+			memcpy(&m.id, id, sizeof(m.id));
+			cn_netlink_send(&m, ctl->group);
+		}
+	}
+	spin_unlock_bh(&notify_lock);
+}
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *))
+{
+	int err;
+	struct cn_dev *dev = &cdev;
+	struct cn_callback *cb;
+
+	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
+	if (!cb) {
+		printk(KERN_INFO "%s: Failed to allocate new struct cn_callback.\n",
+		       dev->cbdev->name);
+		return -ENOMEM;
+	}
+
+	memset(cb, 0, sizeof(*cb));
+
+	snprintf(cb->name, sizeof(cb->name), "%s", name);
+
+	memcpy(&cb->id, id, sizeof(cb->id));
+	cb->callback = callback;
+
+	atomic_set(&cb->refcnt, 0);
+
+	err = cn_queue_add_callback(dev->cbdev, cb);
+	if (err) {
+		kfree(cb);
+		return err;
+	}
+			
+	cn_notify(id, 0);
+
+	return 0;
+}
+
+void cn_del_callback(struct cb_id *id)
+{
+	struct cn_dev *dev = &cdev;
+	struct cn_callback_entry *n, *__cbq;
+
+	list_for_each_entry_safe(__cbq, n, &dev->cbdev->queue_list, callback_entry) {
+		if (cn_cb_equal(&__cbq->cb->id, id)) {
+			cn_queue_del_callback(dev->cbdev, __cbq->cb);
+			cn_notify(id, 1);
+			break;
+		}
+	}
+}
+
+static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
+{
+	int i;
+	struct cn_notify_req *req1, *req2;
+
+	if (m1->idx_notify_num != m2->idx_notify_num)
+		return 0;
+	
+	if (m1->val_notify_num != m2->val_notify_num)
+		return 0;
+	
+	if (m1->len != m2->len)
+		return 0;
+
+	if ((m1->idx_notify_num + m1->val_notify_num)*sizeof(*req1) != m1->len) {
+		printk(KERN_ERR "Notify entry[idx_num=%x, val_num=%x, len=%u] contains garbage. Removing.\n", 
+				m1->idx_notify_num, m1->val_notify_num, m1->len);
+		return 1;
+	}
+
+	req1 = (struct cn_notify_req *)m1->data;
+	req2 = (struct cn_notify_req *)m2->data;
+	
+	for (i=0; i<m1->idx_notify_num; ++i) {
+		if (memcmp(req1, req2, sizeof(*req1)))
+			return 0;
+
+		req1++;
+		req2++;
+	}
+
+	for (i=0; i<m1->val_notify_num; ++i) {
+		if (memcmp(req1, req2, sizeof(*req1)))
+			return 0;
+
+		req1++;
+		req2++;
+	}
+
+	return 1;
+}
+
+static void cn_callback(void * data)
+{
+	struct cn_msg *msg = (struct cn_msg *)data;
+	struct cn_ctl_msg *ctl;
+	struct cn_ctl_entry *ent;
+	u32 size;
+ 
+	if (msg->len < sizeof(*ctl)) {
+		printk(KERN_ERR "Wrong connector request size %u, must be >= %u.\n", 
+				msg->len, sizeof(*ctl));
+		return;
+	}
+	
+	ctl = (struct cn_ctl_msg *)msg->data;
+
+	size = sizeof(*ctl) + (ctl->idx_notify_num + ctl->val_notify_num)*sizeof(struct cn_notify_req);
+
+	if (msg->len != size) {
+		printk(KERN_ERR "Wrong connector request size %u, must be == %u.\n", 
+				msg->len, size);
+		return;
+	}
+
+	if (ctl->len + sizeof(*ctl) != msg->len) {
+		printk(KERN_ERR "Wrong message: msg->len=%u must be equal to inner_len=%u [+%u].\n", 
+				msg->len, ctl->len, sizeof(*ctl));
+		return;
+	}
+
+	/*
+	 * Remove notification.
+	 */
+	if (ctl->group == 0) {
+		struct cn_ctl_entry *n;
+		
+		spin_lock_bh(&notify_lock);
+		list_for_each_entry_safe(ent, n, &notify_list, notify_entry) {
+			if (cn_ctl_msg_equals(ent->msg, ctl)) {
+				list_del(&ent->notify_entry);
+				kfree(ent);
+			}
+		}
+		spin_unlock_bh(&notify_lock);
+
+		return;
+	}
+
+	size += sizeof(*ent);
+
+	ent = kmalloc(size, GFP_ATOMIC);
+	if (!ent) {
+		printk(KERN_ERR "Failed to allocate %d bytes for new notify entry.\n", size);
+		return;
+	}
+
+	memset(ent, 0, size);
+
+	ent->msg = (struct cn_ctl_msg *)(ent + 1);
+
+	memcpy(ent->msg, ctl, size - sizeof(*ent));
+
+	spin_lock_bh(&notify_lock);
+	list_add(&ent->notify_entry, &notify_list);
+	spin_unlock_bh(&notify_lock);
+
+	{
+		int i;
+		struct cn_notify_req *req;
+	
+		printk("Notify group %x for idx: ", ctl->group);
+
+		req = (struct cn_notify_req *)ctl->data;
+		for (i=0; i<ctl->idx_notify_num; ++i, ++req) {
+			printk("%u-%u ", req->first, req->first+req->range-1);
+		}
+		
+		printk("\nNotify group %x for val: ", ctl->group);
+
+		for (i=0; i<ctl->val_notify_num; ++i, ++req) {
+			printk("%u-%u ", req->first, req->first+req->range-1);
+		}
+		printk("\n");
+	}
+}
+
+static int cn_init(void)
+{
+	struct cn_dev *dev = &cdev;
+	int err;
+
+	dev->input = cn_input;
+	dev->id.idx = cn_idx;
+	dev->id.val = cn_val;
+
+	dev->nls = netlink_kernel_create(unit, dev->input);
+	if (!dev->nls) {
+		printk(KERN_ERR "Failed to create new netlink socket(%u).\n",
+		       unit);
+		return -EIO;
+	}
+
+	dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);
+	if (!dev->cbdev) {
+		if (dev->nls->sk_socket)
+			sock_release(dev->nls->sk_socket);
+		return -EINVAL;
+	}
+
+	err = cn_add_callback(&dev->id, "connector", &cn_callback);
+	if (err) {
+		cn_queue_free_dev(dev->cbdev);
+		if (dev->nls->sk_socket)
+			sock_release(dev->nls->sk_socket);
+		return -EINVAL;
+	}
+
+	cn_already_initialized = 1;
+
+	return 0;
+}
+
+static void cn_fini(void)
+{
+	struct cn_dev *dev = &cdev;
+
+	cn_del_callback(&dev->id);
+	cn_queue_free_dev(dev->cbdev);
+	if (dev->nls->sk_socket)
+		sock_release(dev->nls->sk_socket);
+}
+
+module_init(cn_init);
+module_exit(cn_fini);
+
+EXPORT_SYMBOL_GPL(cn_add_callback);
+EXPORT_SYMBOL_GPL(cn_del_callback);
+EXPORT_SYMBOL_GPL(cn_netlink_send);
diff -Nru a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
--- a/drivers/i2c/algos/i2c-algo-ite.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/algos/i2c-algo-ite.c	2005-03-30 17:24:44 -08:00
@@ -713,14 +713,11 @@
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm iic_algo = {
-	"ITE IIC algorithm",
-	I2C_ALGO_IIC,
-	iic_xfer,		/* master_xfer	*/
-	NULL,				/* smbus_xfer	*/
-	NULL,				/* slave_xmit		*/
-	NULL,				/* slave_recv		*/
-	algo_control,			/* ioctl		*/
-	iic_func,			/* functionality	*/
+	.name		= "ITE IIC algorithm",
+	.id		= I2C_ALGO_IIC,
+	.master_xfer	= iic_xfer,
+	.algo_control	= algo_control, /* ioctl */
+	.functionality	= iic_func,
 };
 
 
diff -Nru a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
--- a/drivers/i2c/algos/i2c-algo-pcf.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/algos/i2c-algo-pcf.c	2005-03-30 17:24:44 -08:00
@@ -78,7 +78,6 @@
 	set_pcf(adap, 1, I2C_PCF_STOP);
 }
 
-
 static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
 
 	int timeout = DEF_TIMEOUT;
@@ -109,6 +108,26 @@
 		adap->waitforpin();
 		*status = get_pcf(adap, 1);
 	}
+	if (*status & I2C_PCF_LAB) {
+		DEB2(printk(KERN_INFO 
+			"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+			 *status));
+		/* Cleanup from LAB-- reset and enable ESO.
+		 * This resets the PCF8584; since we've lost the bus, no
+		 * further attempts should be made by callers to clean up 
+		 * (no i2c_stop() etc.)
+		 */
+		set_pcf(adap, 1, I2C_PCF_PIN);
+		set_pcf(adap, 1, I2C_PCF_ESO);
+		/* TODO: we should pause for a time period sufficient for any
+		 * running I2C transaction to complete-- the arbitration
+		 * logic won't work properly until the next START is seen.
+		 */
+		DEB2(printk(KERN_INFO 
+			"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", 
+			get_pcf(adap,1)));
+		return(-EINTR);
+	}
 #endif
 	if (timeout <= 0)
 		return(-1);
@@ -188,16 +207,22 @@
 		       unsigned char addr, int retries)
 {
 	int i, status, ret = -1;
+	int wfp;
 	for (i=0;i<retries;i++) {
 		i2c_outb(adap, addr);
 		i2c_start(adap);
 		status = get_pcf(adap, 1);
-		if (wait_for_pin(adap, &status) >= 0) {
+		if ((wfp = wait_for_pin(adap, &status)) >= 0) {
 			if ((status & I2C_PCF_LRB) == 0) { 
 				i2c_stop(adap);
 				break;	/* success! */
 			}
 		}
+		if (wfp == -EINTR) {
+			/* arbitration lost */
+			udelay(adap->udelay);
+			return -EINTR;
+		}
 		i2c_stop(adap);
 		udelay(adap->udelay);
 	}
@@ -219,6 +244,10 @@
 		i2c_outb(adap, buf[wrcount]);
 		timeout = wait_for_pin(adap, &status);
 		if (timeout) {
+			if (timeout == -EINTR) {
+				/* arbitration lost */
+				return -EINTR;
+			}
 			i2c_stop(adap);
 			dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
 			return -EREMOTEIO; /* got a better one ?? */
@@ -247,11 +276,16 @@
 {
 	int i, status;
 	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+	int wfp;
 
 	/* increment number of bytes to read by one -- read dummy byte */
 	for (i = 0; i <= count; i++) {
 
-		if (wait_for_pin(adap, &status)) {
+		if ((wfp = wait_for_pin(adap, &status))) {
+			if (wfp == -EINTR) {
+				/* arbitration lost */
+				return -EINTR;
+			}
 			i2c_stop(adap);
 			dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
 			return (-1);
@@ -366,6 +400,10 @@
 		/* Wait for PIN (pending interrupt NOT) */
 		timeout = wait_for_pin(adap, &status);
 		if (timeout) {
+			if (timeout == -EINTR) {
+				/* arbitration lost */
+				return (-EINTR);
+			}
 			i2c_stop(adap);
 			DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
 				    "for PIN(1) in pcf_xfer\n");)
diff -Nru a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
--- a/drivers/i2c/algos/i2c-algo-sibyte.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/algos/i2c-algo-sibyte.c	2005-03-30 17:24:44 -08:00
@@ -136,14 +136,11 @@
 /* -----exported algorithm data: -------------------------------------	*/
 
 static struct i2c_algorithm i2c_sibyte_algo = {
-	"SiByte algorithm",
-	I2C_ALGO_SIBYTE,
-	NULL,                           /* master_xfer          */
-	smbus_xfer,                   	/* smbus_xfer           */
-	NULL,				/* slave_xmit		*/
-	NULL,				/* slave_recv		*/
-	algo_control,			/* ioctl		*/
-	bit_func,			/* functionality	*/
+	.name		= "SiByte algorithm",
+	.id		= I2C_ALGO_SIBYTE,
+	.smbus_xfer	= smbus_xfer,
+	.algo_control	= algo_control, /* ioctl */
+	.functionality	= bit_func,
 };
 
 /* 
diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/busses/Kconfig	2005-03-30 17:24:44 -08:00
@@ -108,7 +108,7 @@
 	  will be called i2c-hydra.
 
 config I2C_I801
-	tristate "Intel 801"
+	tristate "Intel 82801 (ICH)"
 	depends on I2C && PCI && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the Intel
@@ -119,7 +119,7 @@
 	    82801BA
 	    82801CA/CAM
 	    82801DB
-	    82801EB
+	    82801EB/ER (ICH5/ICH5R)
 	    6300ESB
 	    ICH6
 	    ICH7
@@ -143,6 +143,23 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i810.
 
+config I2C_PIIX4
+	tristate "Intel PIIX4"
+	depends on I2C && PCI
+	help
+	  If you say yes to this option, support will be included for the Intel
+	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
+	  versions of the chipset are supported:
+	    Intel PIIX4
+	    Intel 440MX
+	    Serverworks OSB4
+	    Serverworks CSB5
+	    Serverworks CSB6
+	    SMSC Victory66
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-piix4.
+
 config I2C_IBM_IIC
 	tristate "IBM PPC 4xx on-chip I2C interface"
 	depends on IBM_OCP && I2C
@@ -284,23 +301,6 @@
 
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-parport-light.
-
-config I2C_PIIX4
-	tristate "Intel PIIX4"
-	depends on I2C && PCI && EXPERIMENTAL
-	help
-	  If you say yes to this option, support will be included for the Intel
-	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
-	  versions of the chipset are supported:
-	    Intel PIIX4
-	    Intel 440MX
-	    Serverworks OSB4
-	    Serverworks CSB5
-	    Serverworks CSB6
-	    SMSC Victory66
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called i2c-piix4.
 
 config I2C_PROSAVAGE
 	tristate "S3/VIA (Pro)Savage"
diff -Nru a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
--- a/drivers/i2c/busses/i2c-elektor.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/busses/i2c-elektor.c	2005-03-30 17:24:44 -08:00
@@ -110,22 +110,23 @@
 }
 
 static void pcf_isa_waitforpin(void) {
-
+	DEFINE_WAIT(wait);
 	int timeout = 2;
-	long flags;
+	unsigned long flags;
 
 	if (irq > 0) {
 		spin_lock_irqsave(&lock, flags);
 		if (pcf_pending == 0) {
 			spin_unlock_irqrestore(&lock, flags);
-			if (interruptible_sleep_on_timeout(&pcf_wait,
-								timeout*HZ)) {
+			prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
+			if (schedule_timeout(timeout*HZ)) {
 				spin_lock_irqsave(&lock, flags);
 				if (pcf_pending == 1) {
 					pcf_pending = 0;
 				}
 				spin_unlock_irqrestore(&lock, flags);
 			}
+			finish_wait(&pcf_wait, &wait);
 		} else {
 			pcf_pending = 0;
 			spin_unlock_irqrestore(&lock, flags);
diff -Nru a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
--- a/drivers/i2c/busses/i2c-ibm_iic.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/busses/i2c-ibm_iic.c	2005-03-30 17:24:44 -08:00
@@ -630,10 +630,6 @@
 	.name 		= "IBM IIC algorithm",
 	.id   		= I2C_ALGO_OCP,
 	.master_xfer 	= iic_xfer,
-	.smbus_xfer	= NULL,
-	.slave_send	= NULL,
-	.slave_recv	= NULL,
-	.algo_control	= NULL,
 	.functionality	= iic_func
 };
 
diff -Nru a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
--- a/drivers/i2c/busses/i2c-ite.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/busses/i2c-ite.c	2005-03-30 17:24:44 -08:00
@@ -40,6 +40,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/wait.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -107,7 +108,7 @@
  * IIC controller interrupts.
  */
 static void iic_ite_waitforpin(void) {
-
+   DEFINE_WAIT(wait);
    int timeout = 2;
    long flags;
 
@@ -121,13 +122,15 @@
 	spin_lock_irqsave(&lock, flags);
 	if (iic_pending == 0) {
 		spin_unlock_irqrestore(&lock, flags);
-		if (interruptible_sleep_on_timeout(&iic_wait, timeout*HZ)) {
+		prepare_to_wait(&iic_wait, &wait, TASK_INTERRUPTIBLE);
+		if (schedule_timeout(timeout*HZ)) {
 			spin_lock_irqsave(&lock, flags);
 			if (iic_pending == 1) {
 				iic_pending = 0;
 			}
 			spin_unlock_irqrestore(&lock, flags);
 		}
+		finish_wait(&iic_wait, &wait);
 	} else {
 		iic_pending = 0;
 		spin_unlock_irqrestore(&lock, flags);
diff -Nru a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
--- a/drivers/i2c/busses/i2c-s3c2410.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/busses/i2c-s3c2410.c	2005-03-30 17:24:44 -08:00
@@ -1,6 +1,6 @@
 /* linux/drivers/i2c/busses/i2c-s3c2410.c
  *
- * Copyright (C) 2004 Simtec Electronics
+ * Copyright (C) 2004,2005 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 I2C Controller
@@ -188,6 +188,9 @@
 	} else
 		stat |= S3C2410_IICSTAT_MASTER_TX;
 
+	if (msg->flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+
 	// todo - check for wether ack wanted or not
 	s3c24xx_i2c_enable_ack(i2c);
 
@@ -287,7 +290,7 @@
 		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
 			/* ack was not received... */
 
-			dev_err(i2c->dev, "ack was not received\n" );
+			dev_dbg(i2c->dev, "ack was not received\n");
 			s3c24xx_i2c_stop(i2c, -EREMOTEIO);
 			goto out_ack;
 		}
@@ -555,11 +558,18 @@
 	return -EREMOTEIO;
 }
 
+/* declare our i2c functionality */
+static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
 /* i2c bus registration info */
 
 static struct i2c_algorithm s3c24xx_i2c_algorithm = {
 	.name			= "S3C2410-I2C-Algorithm",
 	.master_xfer		= s3c24xx_i2c_xfer,
+	.functionality		= s3c24xx_i2c_func,
 };
 
 static struct s3c24xx_i2c s3c24xx_i2c = {
@@ -567,6 +577,7 @@
 	.wait	= __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
 	.adap	= {
 		.name			= "s3c2410-i2c",
+		.owner			= THIS_MODULE,
 		.algo			= &s3c24xx_i2c_algorithm,
 		.retries		= 2,
 		.class			= I2C_CLASS_HWMON,
diff -Nru a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
--- a/drivers/i2c/busses/i2c-viapro.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/busses/i2c-viapro.c	2005-03-30 17:24:44 -08:00
@@ -121,12 +121,12 @@
 		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
-	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
 		dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
 				"Resetting...\n", temp);
 		
 		outb_p(temp, SMBHSTSTS);
-		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
 			dev_dbg(&vt596_adapter.dev, "Failed! (0x%02x)\n", temp);
 			
 			return -1;
@@ -168,13 +168,14 @@
 		dev_dbg(&vt596_adapter.dev, "Error: no response!\n");
 	}
 
-	if (inb_p(SMBHSTSTS) != 0x00)
-		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-
-	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_dbg(&vt596_adapter.dev, "Failed reset at end of "
-			"transaction (%02x)\n", temp);
+	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+		outb_p(temp, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+			dev_warn(&vt596_adapter.dev, "Failed reset at end "
+				 "of transaction (%02x)\n", temp);
+		}
 	}
+
 	dev_dbg(&vt596_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), 
diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
--- a/drivers/i2c/chips/Kconfig	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/Kconfig	2005-03-30 17:24:44 -08:00
@@ -233,9 +233,23 @@
 	  LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
 	  MAX6658 sensor chips.
 
+	  The Analog Devices ADT7461 sensor chip is also supported, but only
+	  if found in ADM1032 compatibility mode.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm90.
 
+config SENSORS_LM92
+	tristate "National Semiconductor LM92 and compatibles"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for National Semiconductor LM92
+	  and Maxim MAX6635 sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm92.
+
 config SENSORS_MAX1619
 	tristate "Maxim MAX1619 sensor chip"
 	depends on I2C && EXPERIMENTAL
@@ -350,6 +364,17 @@
 
 menu "Other I2C Chip support"
 	depends on I2C
+
+config SENSORS_DS1337
+	tristate "Dallas Semiconductor DS1337 Real Time Clock"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for Dallas Semiconductor
+	  DS1337 real-time clock chips. 
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ds1337.
 
 config SENSORS_EEPROM
 	tristate "EEPROM reader"
diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
--- a/drivers/i2c/chips/Makefile	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/Makefile	2005-03-30 17:24:44 -08:00
@@ -11,6 +11,7 @@
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
 obj-$(CONFIG_SENSORS_ADM1026)	+= adm1026.o
 obj-$(CONFIG_SENSORS_ADM1031)	+= adm1031.o
+obj-$(CONFIG_SENSORS_DS1337)	+= ds1337.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
 obj-$(CONFIG_SENSORS_FSCHER)	+= fscher.o
@@ -27,6 +28,7 @@
 obj-$(CONFIG_SENSORS_LM85)	+= lm85.o
 obj-$(CONFIG_SENSORS_LM87)	+= lm87.o
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
+obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
 obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
--- a/drivers/i2c/chips/adm1021.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/adm1021.c	2005-03-30 17:24:44 -08:00
@@ -28,18 +28,6 @@
 #include <linux/i2c-sensor.h>
 
 
-/* Registers */
-#define ADM1021_SYSCTL_TEMP		1200
-#define ADM1021_SYSCTL_REMOTE_TEMP	1201
-#define ADM1021_SYSCTL_DIE_CODE		1202
-#define ADM1021_SYSCTL_ALARMS		1203
-
-#define ADM1021_ALARM_TEMP_HIGH		0x40
-#define ADM1021_ALARM_TEMP_LOW		0x20
-#define ADM1021_ALARM_RTEMP_HIGH	0x10
-#define ADM1021_ALARM_RTEMP_LOW		0x08
-#define ADM1021_ALARM_RTEMP_NA		0x04
-
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
 					0x29, 0x2a, 0x2b,
@@ -380,7 +368,7 @@
 		data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP);
 		data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
 		data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
-		data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec;
+		data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
 		if (data->type == adm1021)
 			data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE);
 		if (data->type == adm1023) {
diff -Nru a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/i2c/chips/ds1337.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,402 @@
+/*
+ *  linux/drivers/i2c/chips/ds1337.c
+ *
+ *  Copyright (C) 2005 James Chapman <jchapman@katalix.com>
+ *
+ *	based on linux/drivers/acron/char/pcf8583.c
+ *  Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for Dallas Semiconductor DS1337 real time clock chip
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/string.h>
+#include <linux/rtc.h>		/* get the user-level API */
+#include <linux/bcd.h>
+#include <linux/list.h>
+
+/* Device registers */
+#define DS1337_REG_HOUR		2
+#define DS1337_REG_DAY		3
+#define DS1337_REG_DATE		4
+#define DS1337_REG_MONTH	5
+#define DS1337_REG_CONTROL	14
+#define DS1337_REG_STATUS	15
+
+/* FIXME - how do we export these interface constants? */
+#define DS1337_GET_DATE		0
+#define DS1337_SET_DATE		1
+
+/*
+ * Functions declaration
+ */
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+SENSORS_INSMOD_1(ds1337);
+
+static int ds1337_attach_adapter(struct i2c_adapter *adapter);
+static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
+static void ds1337_init_client(struct i2c_client *client);
+static int ds1337_detach_client(struct i2c_client *client);
+static int ds1337_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg);
+
+/*
+ * Driver data (common to all clients)
+ */
+static struct i2c_driver ds1337_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "ds1337",
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= ds1337_attach_adapter,
+	.detach_client	= ds1337_detach_client,
+	.command	= ds1337_command,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+struct ds1337_data {
+	struct i2c_client client;
+	struct list_head list;
+	int id;
+};
+
+/*
+ * Internal variables
+ */
+static int ds1337_id;
+static LIST_HEAD(ds1337_clients);
+
+static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
+{
+	s32 tmp = i2c_smbus_read_byte_data(client, reg);
+
+	if (tmp < 0)
+		return -EIO;
+
+	*value = tmp;
+
+	return 0;
+}
+
+/*
+ * Chip access functions
+ */
+static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+	struct ds1337_data *data = i2c_get_clientdata(client);
+	int result;
+	u8 buf[7];
+	u8 val;
+	struct i2c_msg msg[2];
+	u8 offs = 0;
+
+	if (!dt) {
+		dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
+			__FUNCTION__);
+
+		return -EINVAL;
+	}
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &offs;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = sizeof(buf);
+	msg[1].buf = &buf[0];
+
+	result = client->adapter->algo->master_xfer(client->adapter,
+						    &msg[0], 2);
+
+	dev_dbg(&client->adapter->dev,
+		"%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
+		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6]);
+
+	if (result >= 0) {
+		dt->tm_sec = BCD_TO_BIN(buf[0]);
+		dt->tm_min = BCD_TO_BIN(buf[1]);
+		val = buf[2] & 0x3f;
+		dt->tm_hour = BCD_TO_BIN(val);
+		dt->tm_wday = BCD_TO_BIN(buf[3]) - 1;
+		dt->tm_mday = BCD_TO_BIN(buf[4]);
+		val = buf[5] & 0x7f;
+		dt->tm_mon = BCD_TO_BIN(val);
+		dt->tm_year = 1900 + BCD_TO_BIN(buf[6]);
+		if (buf[5] & 0x80)
+			dt->tm_year += 100;
+
+		dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, "
+			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+			__FUNCTION__, dt->tm_sec, dt->tm_min,
+			dt->tm_hour, dt->tm_mday,
+			dt->tm_mon, dt->tm_year, dt->tm_wday);
+	} else {
+		dev_err(&client->adapter->dev, "ds1337[%d]: error reading "
+			"data! %d\n", data->id, result);
+		result = -EIO;
+	}
+
+	return result;
+}
+
+static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+	struct ds1337_data *data = i2c_get_clientdata(client);
+	int result;
+	u8 buf[8];
+	u8 val;
+	struct i2c_msg msg[1];
+
+	if (!dt) {
+		dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
+			__FUNCTION__);
+
+		return -EINVAL;
+	}
+
+	dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
+		dt->tm_sec, dt->tm_min, dt->tm_hour,
+		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
+
+	buf[0] = 0;		/* reg offset */
+	buf[1] = BIN_TO_BCD(dt->tm_sec);
+	buf[2] = BIN_TO_BCD(dt->tm_min);
+	buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6);
+	buf[4] = BIN_TO_BCD(dt->tm_wday) + 1;
+	buf[5] = BIN_TO_BCD(dt->tm_mday);
+	buf[6] = BIN_TO_BCD(dt->tm_mon);
+	if (dt->tm_year >= 2000) {
+		val = dt->tm_year - 2000;
+		buf[6] |= (1 << 7);
+	} else {
+		val = dt->tm_year - 1900;
+	}
+	buf[7] = BIN_TO_BCD(val);
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = sizeof(buf);
+	msg[0].buf = &buf[0];
+
+	result = client->adapter->algo->master_xfer(client->adapter,
+						    &msg[0], 1);
+	if (result < 0) {
+		dev_err(&client->adapter->dev, "ds1337[%d]: error "
+			"writing data! %d\n", data->id, result);
+		result = -EIO;
+	} else {
+		result = 0;
+	}
+
+	return result;
+}
+
+static int ds1337_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg)
+{
+	dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
+
+	switch (cmd) {
+	case DS1337_GET_DATE:
+		return ds1337_get_datetime(client, arg);
+
+	case DS1337_SET_DATE:
+		return ds1337_set_datetime(client, arg);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * Public API for access to specific device. Useful for low-level
+ * RTC access from kernel code.
+ */
+int ds1337_do_command(int id, int cmd, void *arg)
+{
+	struct list_head *walk;
+	struct list_head *tmp;
+	struct ds1337_data *data;
+
+	list_for_each_safe(walk, tmp, &ds1337_clients) {
+		data = list_entry(walk, struct ds1337_data, list);
+		if (data->id == id)
+			return ds1337_command(&data->client, cmd, arg);
+	}
+
+	return -ENODEV;
+}
+
+static int ds1337_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, ds1337_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct ds1337_data *data;
+	int err = 0;
+	const char *name = "";
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_I2C))
+		goto exit;
+
+	if (!(data = kmalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct ds1337_data));
+	INIT_LIST_HEAD(&data->list);
+
+	/* The common I2C client data is placed right before the
+	 * DS1337-specific data. 
+	 */
+	new_client = &data->client;
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &ds1337_driver;
+	new_client->flags = 0;
+
+	/*
+	 * Now we do the remaining detection. A negative kind means that
+	 * the driver was loaded with no force parameter (default), so we
+	 * must both detect and identify the chip. A zero kind means that
+	 * the driver was loaded with the force parameter, the detection
+	 * step shall be skipped. A positive kind means that the driver
+	 * was loaded with the force parameter and a given kind of chip is
+	 * requested, so both the detection and the identification steps
+	 * are skipped.
+	 *
+	 * For detection, we read registers that are most likely to cause
+	 * detection failure, i.e. those that have more bits with fixed
+	 * or reserved values.
+	 */
+
+	/* Default to an DS1337 if forced */
+	if (kind == 0)
+		kind = ds1337;
+
+	if (kind < 0) {		/* detection and identification */
+		u8 data;
+
+		/* Check that status register bits 6-2 are zero */
+		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
+		    (data & 0x7c))
+			goto exit_free;
+
+		/* Check for a valid day register value */
+		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
+		    (data == 0) || (data & 0xf8))
+			goto exit_free;
+
+		/* Check for a valid date register value */
+		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
+		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
+		    (data >= 0x32))
+			goto exit_free;
+
+		/* Check for a valid month register value */
+		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
+		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
+		    ((data >= 0x13) && (data <= 0x19)))
+			goto exit_free;
+
+		/* Check that control register bits 6-5 are zero */
+		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
+		    (data & 0x60))
+			goto exit_free;
+
+		kind = ds1337;
+	}
+
+	if (kind == ds1337)
+		name = "ds1337";
+
+	/* We can fill in the remaining client fields */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Initialize the DS1337 chip */
+	ds1337_init_client(new_client);
+
+	/* Add client to local list */
+	data->id = ds1337_id++;
+	list_add(&data->list, &ds1337_clients);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static void ds1337_init_client(struct i2c_client *client)
+{
+	s32 val;
+
+	/* Ensure that device is set in 24-hour mode */
+	val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
+	if ((val >= 0) && (val & (1 << 6)) == 0)
+		i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
+					  val | (1 << 6));
+}
+
+static int ds1337_detach_client(struct i2c_client *client)
+{
+	int err;
+	struct ds1337_data *data = i2c_get_clientdata(client);
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	list_del(&data->list);
+	kfree(data);
+	return 0;
+}
+
+static int __init ds1337_init(void)
+{
+	return i2c_add_driver(&ds1337_driver);
+}
+
+static void __exit ds1337_exit(void)
+{
+	i2c_del_driver(&ds1337_driver);
+}
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("DS1337 RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(ds1337_init);
+module_exit(ds1337_exit);
diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
--- a/drivers/i2c/chips/eeprom.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/eeprom.c	2005-03-30 17:24:44 -08:00
@@ -210,10 +210,11 @@
 		if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
 		 && i2c_smbus_read_byte(new_client) == 'C'
 		 && i2c_smbus_read_byte(new_client) == 'G'
-		 && i2c_smbus_read_byte(new_client) == '-')
+		 && i2c_smbus_read_byte(new_client) == '-') {
 			dev_info(&new_client->dev, "Vaio EEPROM detected, "
 				"enabling password protection\n");
 			data->nature = VAIO;
+		}
 	}
 
 	/* create the sysfs eeprom file */
diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c
--- a/drivers/i2c/chips/it87.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/it87.c	2005-03-30 17:24:44 -08:00
@@ -734,10 +734,9 @@
 			goto ERROR0;
 
 	/* Probe whether there is anything available on this address. Already
-	   done for SMBus clients */
+	   done for SMBus and Super-I/O clients */
 	if (kind < 0) {
-		if (is_isa) {
-
+		if (is_isa && !chip_type) {
 #define REALLY_SLOW_IO
 			/* We need the timeouts for at least some IT87-like chips. But only
 			   if we read 'undefined' registers. */
@@ -890,9 +889,9 @@
 	}
 
 	if (data->type == it8712) {
+		data->vrm = i2c_which_vrm();
 		device_create_file_vrm(new_client);
 		device_create_file_vid(new_client);
-		data->vrm = i2c_which_vrm();
 	}
 
 	return 0;
@@ -1122,9 +1121,6 @@
 			data->temp_low[i] =
 			    it87_read_value(client, IT87_REG_TEMP_LOW(i));
 		}
-
-		/* The 8705 does not have VID capability */
-		data->vid = 0x1f;
 
 		i = it87_read_value(client, IT87_REG_FAN_DIV);
 		data->fan_div[0] = i & 0x07;
diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c
--- a/drivers/i2c/chips/lm85.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/lm85.c	2005-03-30 17:24:44 -08:00
@@ -37,7 +37,7 @@
 static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_5(lm85b, lm85c, adm1027, adt7463, emc6d100);
+SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 
 /* The LM85 registers */
 
@@ -74,8 +74,10 @@
 #define	LM85_VERSTEP_LM85B		0x62
 #define	LM85_VERSTEP_ADM1027		0x60
 #define	LM85_VERSTEP_ADT7463		0x62
+#define	LM85_VERSTEP_ADT7463C		0x6A
 #define	LM85_VERSTEP_EMC6D100_A0        0x60
 #define	LM85_VERSTEP_EMC6D100_A1        0x61
+#define	LM85_VERSTEP_EMC6D102		0x65
 
 #define	LM85_REG_CONFIG			0x40
 
@@ -112,9 +114,13 @@
 
 #define EMC6D100_REG_ALARM3             0x7d
 /* IN5, IN6 and IN7 */
-#define EMC6D100_REG_IN(nr)             (0x70 + ((nr)-5))
-#define EMC6D100_REG_IN_MIN(nr)         (0x73 + ((nr)-5) * 2)
-#define EMC6D100_REG_IN_MAX(nr)         (0x74 + ((nr)-5) * 2)
+#define	EMC6D100_REG_IN(nr)             (0x70 + ((nr)-5))
+#define	EMC6D100_REG_IN_MIN(nr)         (0x73 + ((nr)-5) * 2)
+#define	EMC6D100_REG_IN_MAX(nr)         (0x74 + ((nr)-5) * 2)
+#define	EMC6D102_REG_EXTEND_ADC1	0x85
+#define	EMC6D102_REG_EXTEND_ADC2	0x86
+#define	EMC6D102_REG_EXTEND_ADC3	0x87
+#define	EMC6D102_REG_EXTEND_ADC4	0x88
 
 #define	LM85_ALARM_IN0			0x0001
 #define	LM85_ALARM_IN1			0x0002
@@ -139,35 +145,36 @@
    these macros are called: arguments may be evaluated more than once.
  */
 
-/* IN are scaled 1.000 == 0xc0, mag = 3 */
-#define IN_TO_REG(val)		(SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255))
-#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0)
-#define IN_FROM_REG(val)	(INEXT_FROM_REG(val,0))
-
 /* IN are scaled acording to built-in resistors */
 static int lm85_scaling[] = {  /* .001 Volts */
 		2500, 2250, 3300, 5000, 12000,
 		3300, 1500, 1800 /*EMC6D100*/
 	};
 #define SCALE(val,from,to)		(((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n,val)		(SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255))
-#define INSEXT_FROM_REG(n,val,ext)	(SCALE((val)*4 + (ext),192*4,lm85_scaling[n]))
-#define INS_FROM_REG(n,val)		(INSEXT_FROM_REG(n,val,0))
+
+#define INS_TO_REG(n,val)	\
+		SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)
+
+#define INSEXT_FROM_REG(n,val,ext,scale)	\
+		SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n])
+
+#define INS_FROM_REG(n,val)   INSEXT_FROM_REG(n,val,0,1)
 
 /* FAN speed is measured using 90kHz clock */
 #define FAN_TO_REG(val)		(SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
 #define FAN_FROM_REG(val)	((val)==0?-1:(val)==0xffff?0:5400000/(val))
 
 /* Temperature is reported in .001 degC increments */
-#define TEMP_TO_REG(val)		(SENSORS_LIMIT(((val)+500)/1000,-127,127))
-#define TEMPEXT_FROM_REG(val,ext)	((val)*1000 + (ext)*250)
-#define TEMP_FROM_REG(val)		(TEMPEXT_FROM_REG(val,0))
-#define EXTTEMP_TO_REG(val)		(SENSORS_LIMIT((val)/250,-127,127))
+#define TEMP_TO_REG(val)	\
+		SENSORS_LIMIT(SCALE(val,1000,1),-127,127)
+#define TEMPEXT_FROM_REG(val,ext,scale)	\
+		SCALE((val)*scale + (ext),scale,1000)
+#define TEMP_FROM_REG(val)	\
+		TEMPEXT_FROM_REG(val,0,1)
 
 #define PWM_TO_REG(val)			(SENSORS_LIMIT(val,0,255))
 #define PWM_FROM_REG(val)		(val)
 
-#define EXT_FROM_REG(val,sensor)	(((val)>>(sensor * 2))&0x03)
 
 /* ZONEs have the following parameters:
  *    Limit (low) temp,           1. degC
@@ -355,7 +362,9 @@
 	u8 pwm[3];		/* Register value */
 	u8 spinup_ctl;		/* Register encoding, combined */
 	u8 tach_mode;		/* Register encoding, combined */
-	u16 extend_adc;		/* Register value */
+	u8 temp_ext[3];		/* Decoded values */
+	u8 in_ext[8];		/* Decoded values */
+	u8 adc_scale;		/* ADC Extended bits scaling factor */
 	u8 fan_ppr;		/* Register value */
 	u8 smooth[3];		/* Register encoding */
 	u8 vid;			/* Register value */
@@ -536,7 +545,10 @@
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
 	struct lm85_data *data = lm85_update_device(dev);
-	return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr]) );
+	return sprintf(	buf, "%d\n", INSEXT_FROM_REG(nr,
+						     data->in[nr],
+						     data->in_ext[nr],
+						     data->adc_scale) );
 }
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
 {
@@ -617,7 +629,9 @@
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
 {
 	struct lm85_data *data = lm85_update_device(dev);
-	return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr]) );
+	return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr],
+						    data->temp_ext[nr],
+						    data->adc_scale) );
 }
 static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
 {
@@ -1089,7 +1103,8 @@
 		    && verstep == LM85_VERSTEP_ADM1027 ) {
 			kind = adm1027 ;
 		} else if( company == LM85_COMPANY_ANALOG_DEV
-		    && verstep == LM85_VERSTEP_ADT7463 ) {
+		    && (verstep == LM85_VERSTEP_ADT7463
+			 || verstep == LM85_VERSTEP_ADT7463C) ) {
 			kind = adt7463 ;
 		} else if( company == LM85_COMPANY_ANALOG_DEV
 		    && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) {
@@ -1107,6 +1122,9 @@
 			 */
 			kind = emc6d100 ;
 		} else if( company == LM85_COMPANY_SMSC
+		    && verstep == LM85_VERSTEP_EMC6D102) {
+			kind = emc6d102 ;
+		} else if( company == LM85_COMPANY_SMSC
 		    && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) {
 			dev_err(&adapter->dev, "lm85: Detected SMSC chip\n");
 			dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x"
@@ -1142,6 +1160,8 @@
 		type_name = "adt7463";
 	} else if ( kind == emc6d100){
 		type_name = "emc6d100";
+	} else if ( kind == emc6d102 ) {
+		type_name = "emc6d102";
 	}
 	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
 
@@ -1259,7 +1279,6 @@
 	case LM85_REG_FAN_MIN(2) :
 	case LM85_REG_FAN_MIN(3) :
 	case LM85_REG_ALARM1 :	/* Read both bytes at once */
-	case ADM1027_REG_EXTEND_ADC1 :  /* Read two bytes at once */
 		res = i2c_smbus_read_byte_data(client, reg) & 0xff ;
 		res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ;
 		break ;
@@ -1363,10 +1382,25 @@
 		 * more significant bits that are read later.
 		 */
 		if ( (data->type == adm1027) || (data->type == adt7463) ) {
-			data->extend_adc =
-			    lm85_read_value(client, ADM1027_REG_EXTEND_ADC1);
+			int ext1 = lm85_read_value(client,
+						   ADM1027_REG_EXTEND_ADC1);
+			int ext2 =  lm85_read_value(client,
+						    ADM1027_REG_EXTEND_ADC2);
+			int val = (ext1 << 8) + ext2;
+
+			for(i = 0; i <= 4; i++)
+				data->in_ext[i] = (val>>(i * 2))&0x03;
+
+			for(i = 0; i <= 2; i++)
+				data->temp_ext[i] = (val>>((i + 5) * 2))&0x03;
 		}
 
+		/* adc_scale is 2^(number of LSBs). There are 4 extra bits in
+		   the emc6d102 and 2 in the adt7463 and adm1027. In all
+		   other chips ext is always 0 and the value of scale is
+		   irrelevant. So it is left in 4*/
+		data->adc_scale = (data->type == emc6d102 ) ? 16 : 4;
+
 		for (i = 0; i <= 4; ++i) {
 			data->in[i] =
 			    lm85_read_value(client, LM85_REG_IN(i));
@@ -1403,6 +1437,28 @@
 			/* More alarm bits */
 			data->alarms |=
 				lm85_read_value(client, EMC6D100_REG_ALARM3) << 16;
+		} else if (data->type == emc6d102 ) {
+			/* Have to read LSB bits after the MSB ones because
+			   the reading of the MSB bits has frozen the
+			   LSBs (backward from the ADM1027).
+			 */
+			int ext1 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC1);
+			int ext2 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC2);
+			int ext3 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC3);
+			int ext4 = lm85_read_value(client,
+						   EMC6D102_REG_EXTEND_ADC4);
+			data->in_ext[0] = ext3 & 0x0f;
+			data->in_ext[1] = ext4 & 0x0f;
+			data->in_ext[2] = (ext4 >> 4) & 0x0f;
+			data->in_ext[3] = (ext3 >> 4) & 0x0f;
+			data->in_ext[4] = (ext2 >> 4) & 0x0f;
+
+			data->temp_ext[0] = ext1 & 0x0f;
+			data->temp_ext[1] = ext2 & 0x0f;
+			data->temp_ext[2] = (ext1 >> 4) & 0x0f;
 		}
 
 		data->last_reading = jiffies ;
diff -Nru a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c
--- a/drivers/i2c/chips/lm87.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/lm87.c	2005-03-30 17:24:44 -08:00
@@ -317,20 +317,20 @@
 
 static void set_temp_low(struct device *dev, const char *buf, int nr)
 {
-    struct i2c_client *client = to_i2c_client(dev);
-    struct lm87_data *data = i2c_get_clientdata(client);
-    long val = simple_strtol(buf, NULL, 10);
-    data->temp_low[nr] = TEMP_TO_REG(val);
-    lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+	data->temp_low[nr] = TEMP_TO_REG(val);
+	lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
 }
 
 static void set_temp_high(struct device *dev, const char *buf, int nr)
 {
-    struct i2c_client *client = to_i2c_client(dev);
-    struct lm87_data *data = i2c_get_clientdata(client);
-    long val = simple_strtol(buf, NULL, 10);
-    data->temp_high[nr] = TEMP_TO_REG(val);
-    lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm87_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+	data->temp_high[nr] = TEMP_TO_REG(val);
+	lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
 }
 
 #define set_temp(offset) \
diff -Nru a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c
--- a/drivers/i2c/chips/lm90.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/lm90.c	2005-03-30 17:24:44 -08:00
@@ -43,6 +43,14 @@
  * variants. The extra address and features of the MAX6659 are not
  * supported by this driver.
  *
+ * This driver also supports the ADT7461 chip from Analog Devices but
+ * only in its "compatability mode". If an ADT7461 chip is found but
+ * is configured in non-compatible mode (where its temperature
+ * register values are decoded differently) it is ignored by this
+ * driver. Complete datasheet can be obtained from Analog's website
+ * at:
+ *   http://products.analog.com/products/info.asp?product=ADT7461
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
@@ -77,6 +85,7 @@
  * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c.
  * LM89-1, and LM99-1 have address 0x4d.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * ADT7461 always has address 0x4c.
  */
 
 static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
@@ -86,7 +95,7 @@
  * Insmod parameters
  */
 
-SENSORS_INSMOD_5(lm90, adm1032, lm99, lm86, max6657);
+SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
 
 /*
  * The LM90 registers
@@ -148,6 +157,19 @@
 #define HYST_TO_REG(val)	((val) <= 0 ? 0 : (val) >= 30500 ? 31 : \
 				 ((val) + 500) / 1000)
 
+/* 
+ * ADT7461 is almost identical to LM90 except that attempts to write
+ * values that are outside the range 0 < temp < 127 are treated as
+ * the boundary value. 
+ */
+
+#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \
+				 (val) >= 127000 ? 127 : \
+				 ((val) + 500) / 1000)
+#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \
+				 (val) >= 127750 ? 0x7FC0 : \
+				 ((val) + 125) / 250 * 64)
+
 /*
  * Functions declaration
  */
@@ -181,6 +203,7 @@
 	struct semaphore update_lock;
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
+	int kind;
 
 	/* registers values */
 	s8 temp_input1, temp_low1, temp_high1; /* local */
@@ -216,7 +239,10 @@
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm90_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
-	data->value = TEMP1_TO_REG(val); \
+	if (data->kind == adt7461) \
+		data->value = TEMP1_TO_REG_ADT7461(val); \
+	else \
+		data->value = TEMP1_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, reg, data->value); \
 	return count; \
 }
@@ -227,7 +253,10 @@
 	struct i2c_client *client = to_i2c_client(dev); \
 	struct lm90_data *data = i2c_get_clientdata(client); \
 	long val = simple_strtol(buf, NULL, 10); \
-	data->value = TEMP2_TO_REG(val); \
+	if (data->kind == adt7461) \
+		data->value = TEMP2_TO_REG_ADT7461(val); \
+	else \
+		data->value = TEMP2_TO_REG(val); \
 	i2c_smbus_write_byte_data(client, regh, data->value >> 8); \
 	i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \
 	return count; \
@@ -381,6 +410,12 @@
 			 && (reg_config1 & 0x3F) == 0x00
 			 && reg_convrate <= 0x0A) {
 				kind = adm1032;
+			} else
+			if (address == 0x4c
+			 && chip_id == 0x51 /* ADT7461 */
+			 && (reg_config1 & 0x1F) == 0x00 /* check compat mode */
+			 && reg_convrate <= 0x0A) {
+				kind = adt7461;
 			}
 		} else
 		if (man_id == 0x4D) { /* Maxim */
@@ -418,11 +453,14 @@
 		name = "lm86";
 	} else if (kind == max6657) {
 		name = "max6657";
+	} else if (kind == adt7461) {
+		name = "adt7461";
 	}
 
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	data->valid = 0;
+	data->kind = kind;
 	init_MUTEX(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
diff -Nru a/drivers/i2c/chips/lm92.c b/drivers/i2c/chips/lm92.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/i2c/chips/lm92.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,423 @@
+/*
+ * lm92 - Hardware monitoring driver
+ * Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
+ *
+ * Based on the lm90 driver, with some ideas taken from the lm_sensors
+ * lm92 driver as well.
+ *
+ * The LM92 is a sensor chip made by National Semiconductor. It reports
+ * its own temperature with a 0.0625 deg resolution and a 0.33 deg
+ * accuracy. Complete datasheet can be obtained from National's website
+ * at:
+ *   http://www.national.com/pf/LM/LM92.html
+ *
+ * This driver also supports the MAX6635 sensor chip made by Maxim.
+ * This chip is compatible with the LM92, but has a lesser accuracy
+ * (1.0 deg). Complete datasheet can be obtained from Maxim's website
+ * at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
+ *
+ * Since the LM92 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * Support could easily be added for the National Semiconductor LM76
+ * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible
+ * with the LM92.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+
+/* The LM92 and MAX6635 have 2 two-state pins for address selection,
+   resulting in 4 possible addresses. */
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+				       I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(lm92);
+
+/* The LM92 registers */
+#define LM92_REG_CONFIG			0x01 /* 8-bit, RW */
+#define LM92_REG_TEMP			0x00 /* 16-bit, RO */
+#define LM92_REG_TEMP_HYST		0x02 /* 16-bit, RW */
+#define LM92_REG_TEMP_CRIT		0x03 /* 16-bit, RW */
+#define LM92_REG_TEMP_LOW		0x04 /* 16-bit, RW */
+#define LM92_REG_TEMP_HIGH		0x05 /* 16-bit, RW */
+#define LM92_REG_MAN_ID			0x07 /* 16-bit, RO, LM92 only */
+
+/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius,
+   left-justified in 16-bit registers. No rounding is done, with such
+   a resolution it's just not worth it. Note that the MAX6635 doesn't
+   make use of the 4 lower bits for limits (i.e. effective resolution
+   for limits is 1 degree Celsius). */
+static inline int TEMP_FROM_REG(s16 reg)
+{
+	return reg / 8 * 625 / 10;
+}
+
+static inline s16 TEMP_TO_REG(int val)
+{
+	if (val <= -60000)
+		return -60000 * 10 / 625 * 8;
+	if (val >= 160000)
+		return 160000 * 10 / 625 * 8;
+	return val * 10 / 625 * 8;
+}
+
+/* Alarm flags are stored in the 3 LSB of the temperature register */
+static inline u8 ALARMS_FROM_REG(s16 reg)
+{
+	return reg & 0x0007;
+}
+
+/* Driver data (common to all clients) */
+static struct i2c_driver lm92_driver;
+
+/* Client data (each client gets its own) */
+struct lm92_data {
+	struct i2c_client client;
+	struct semaphore update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* registers values */
+	s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst;
+};
+
+
+/*
+ * Sysfs attributes and callback functions
+ */
+
+static struct lm92_data *lm92_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm92_data *data = i2c_get_clientdata(client);
+
+	down(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ)
+	 || !data->valid) {
+		dev_dbg(&client->dev, "Updating lm92 data\n");
+		data->temp1_input = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP));
+		data->temp1_hyst = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_HYST));
+		data->temp1_crit = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_CRIT));
+		data->temp1_min = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_LOW));
+		data->temp1_max = swab16(i2c_smbus_read_word_data(client,
+				    LM92_REG_TEMP_HIGH));
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+#define show_temp(value) \
+static ssize_t show_##value(struct device *dev, char *buf) \
+{ \
+	struct lm92_data *data = lm92_update_device(dev); \
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
+}
+show_temp(temp1_input);
+show_temp(temp1_crit);
+show_temp(temp1_min);
+show_temp(temp1_max);
+
+#define set_temp(value, reg) \
+static ssize_t set_##value(struct device *dev, const char *buf, \
+	size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct lm92_data *data = i2c_get_clientdata(client); \
+	long val = simple_strtol(buf, NULL, 10); \
+	data->value = TEMP_TO_REG(val); \
+	i2c_smbus_write_word_data(client, reg, swab16(data->value)); \
+	return count; \
+}
+set_temp(temp1_crit, LM92_REG_TEMP_CRIT);
+set_temp(temp1_min, LM92_REG_TEMP_LOW);
+set_temp(temp1_max, LM92_REG_TEMP_HIGH);
+
+static ssize_t show_temp1_crit_hyst(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit)
+		       - TEMP_FROM_REG(data->temp1_hyst));
+}
+static ssize_t show_temp1_max_hyst(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max)
+		       - TEMP_FROM_REG(data->temp1_hyst));
+}
+static ssize_t show_temp1_min_hyst(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min)
+		       + TEMP_FROM_REG(data->temp1_hyst));
+}
+
+static ssize_t set_temp1_crit_hyst(struct device *dev, const char *buf,
+	size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm92_data *data = i2c_get_clientdata(client);
+	data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) -
+			   simple_strtol(buf, NULL, 10);
+	i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST,
+				  swab16(TEMP_TO_REG(data->temp1_hyst)));
+	return count;
+}
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct lm92_data *data = lm92_update_device(dev);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input));
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
+static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit,
+	set_temp1_crit);
+static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst,
+	set_temp1_crit_hyst);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min,
+	set_temp1_min);
+static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max,
+	set_temp1_max);
+static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+
+/*
+ * Detection and registration
+ */
+
+static void lm92_init_client(struct i2c_client *client)
+{
+	u8 config;
+
+	/* Start the conversions if needed */
+	config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
+	if (config & 0x01)
+		i2c_smbus_write_byte_data(client, LM92_REG_CONFIG,
+					  config & 0xFE);
+}
+
+/* The MAX6635 has no identification register, so we have to use tricks
+   to identify it reliably. This is somewhat slow.
+   Note that we do NOT rely on the 2 MSB of the configuration register
+   always reading 0, as suggested by the datasheet, because it was once
+   reported not to be true. */
+static int max6635_check(struct i2c_client *client)
+{
+	u16 temp_low, temp_high, temp_hyst, temp_crit;
+	u8 conf;
+	int i;
+
+	/* No manufacturer ID register, so a read from this address will
+	   always return the last read value. */
+	temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW);
+	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low)
+		return 0;
+	temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH);
+	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high)
+		return 0;
+	
+	/* Limits are stored as integer values (signed, 9-bit). */
+	if ((temp_low & 0x7f00) || (temp_high & 0x7f00))
+		return 0;
+	temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST);
+	temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT);
+	if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00))
+		return 0;
+
+	/* Registers addresses were found to cycle over 16-byte boundaries.
+	   We don't test all registers with all offsets so as to save some
+	   reads and time, but this should still be sufficient to dismiss
+	   non-MAX6635 chips. */
+	conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
+	for (i=16; i<96; i*=2) {
+		if (temp_hyst != i2c_smbus_read_word_data(client,
+		 		 LM92_REG_TEMP_HYST + i - 16)
+		 || temp_crit != i2c_smbus_read_word_data(client,
+		 		 LM92_REG_TEMP_CRIT + i)
+		 || temp_low != i2c_smbus_read_word_data(client,
+				LM92_REG_TEMP_LOW + i + 16)
+		 || temp_high != i2c_smbus_read_word_data(client,
+		 		 LM92_REG_TEMP_HIGH + i + 32)
+		 || conf != i2c_smbus_read_byte_data(client,
+		 	    LM92_REG_CONFIG + i))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* 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)
+{
+	struct i2c_client *new_client;
+	struct lm92_data *data;
+	int err = 0;
+	char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+					    | I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(data, 0, sizeof(struct lm92_data));
+
+	/* 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;
+
+	/* A negative kind means that the driver was loaded with no force
+	   parameter (default), so we must identify the chip. */
+	if (kind < 0) {
+		u8 config = i2c_smbus_read_byte_data(new_client,
+			     LM92_REG_CONFIG);
+		u16 man_id = i2c_smbus_read_word_data(new_client,
+			     LM92_REG_MAN_ID);
+
+		if ((config & 0xe0) == 0x00
+		 && man_id == 0x0180) {
+			pr_info("lm92: Found National Semiconductor LM92 chip\n");
+	 		kind = lm92;
+		} else
+		if (max6635_check(new_client)) {
+			pr_info("lm92: Found Maxim MAX6635 chip\n");
+			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;
+	}
+
+	/* Fill in the remaining client fields */
+	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+	data->valid = 0;
+	init_MUTEX(&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 */
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+	device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+
+	return 0;
+
+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_detect(adapter, &addr_data, lm92_detect);
+}
+
+static int lm92_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev, "Client deregistration failed, "
+			"client not detached.\n");
+		return err;
+	}
+
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+
+/*
+ * Module and driver stuff
+ */
+
+static struct i2c_driver lm92_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "lm92",
+	.id		= I2C_DRIVERID_LM92,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= lm92_attach_adapter,
+	.detach_client	= lm92_detach_client,
+};
+
+static int __init sensors_lm92_init(void)
+{
+	return i2c_add_driver(&lm92_driver);
+}
+
+static void __exit sensors_lm92_exit(void)
+{
+	i2c_del_driver(&lm92_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("LM92/MAX6635 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm92_init);
+module_exit(sensors_lm92_exit);
diff -Nru a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
--- a/drivers/i2c/chips/m41t00.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/m41t00.c	2005-03-30 17:24:44 -08:00
@@ -184,7 +184,6 @@
 
 	memset(client, 0, sizeof(struct i2c_client));
 	strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE);
-	client->id = m41t00_driver.id;
 	client->flags = I2C_DF_NOTIFY;
 	client->addr = addr;
 	client->adapter = adap;
diff -Nru a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c
--- a/drivers/i2c/chips/w83627hf.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/chips/w83627hf.c	2005-03-30 17:24:44 -08:00
@@ -304,7 +304,6 @@
 	u32 beep_mask;		/* Register encoding, combined */
 	u8 beep_enable;		/* Boolean */
 	u8 pwm[3];		/* Register value */
-	u8 pwmenable[3];	/* bool */
 	u16 sens[3];		/* 782D/783S only.
 				   1 = pentium diode; 2 = 3904 diode;
 				   3000-5000 = thermistor beta.
@@ -1316,10 +1315,6 @@
 		if ((type == w83697hf) && (i == 2))
 			break;
 	}
-
-	data->pwmenable[0] = 1;
-	data->pwmenable[1] = 1;
-	data->pwmenable[2] = 1;
 
 	if(init) {
 		/* Enable temp2 */
diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
--- a/drivers/i2c/i2c-core.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/i2c/i2c-core.c	2005-03-30 17:24:44 -08:00
@@ -587,7 +587,13 @@
 	int ret;
 
 	if (adap->algo->master_xfer) {
- 	 	dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num);
+#ifdef DEBUG
+		for (ret = 0; ret < num; ret++) {
+			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+				"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
+				'R' : 'W', msgs[ret].addr, msgs[ret].len);
+		}
+#endif
 
 		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,msgs,num);
@@ -709,7 +715,7 @@
 		   at all */
 		found = 0;
 
-		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) {
+		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) {
 			if (((adap_id == address_data->force[i]) || 
 			     (address_data->force[i] == ANY_I2C_BUS)) &&
 			     (addr == address_data->force[i+1])) {
diff -Nru a/drivers/superio/Kconfig b/drivers/superio/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/Kconfig	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,56 @@
+menu "SuperIO subsystem support"
+
+config SC_SUPERIO
+	tristate "SuperIO subsystem support"
+	depends on CONNECTOR
+	help
+	  SuperIO subsystem support.
+	
+	  This support is also available as a module.  If so, the module
+          will be called superio.ko.
+
+config SC_PC8736X
+	tristate "PC8736x SuperIO"
+	depends on SC_SUPERIO
+	help
+	  Say Y here if you want to use PC8736x controller.
+	  It is LPC SuperIO with hardware monitoring chip from National Semiconductor.
+	
+	  This support is also available as a module.  If so, the module
+          will be called pc8736x.ko.
+
+config SC_SCX200
+	tristate "SCx200/SC1100 SuperIO"
+	depends on SC_SUPERIO
+	help
+	  Say Y here if you want to use SCx200/SC1100 controller.
+	  It is Geode system-on-chip processor from AMD(formerly National Semiconductor).
+	
+	  This support is also available as a module.  If so, the module
+          will be called scx200.ko.
+
+
+config SC_GPIO
+	tristate "SuperIO - GPIO"
+	depends on SC_SUPERIO
+	help
+	  Say Y here if you want to use General-Purpose Input/Output (GPIO) pins.
+	
+	  This support is also available as a module.  If so, the module
+          will be called sc_gpio.ko.
+
+config SC_ACB
+	tristate "SuperIO - Access Bus"
+	depends on SC_SUPERIO
+	help
+	  Say Y here if you want to use Access Bus.
+	  The ACB is a two-wire synchronous serial interface compatible with the ACCESS.bus physical layer. 
+	  The ACB is also compatible with Intel's SMBus and Philips' I2C. 
+	  The ACB allows easy interfacing to a wide range of low-cost memories and I/O devices, 
+	  including EEPROMs, SRAMs, timers, ADC, DAC, clock chips and peripheral drivers.
+	
+	  This support is also available as a module.  If so, the module
+          will be called sc_acb.ko.
+
+
+endmenu
diff -Nru a/drivers/superio/Makefile b/drivers/superio/Makefile
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/Makefile	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,11 @@
+#
+# Makefile for the SuperIO subsystem.
+#
+
+obj-$(CONFIG_SC_SUPERIO)	+= superio.o
+obj-$(CONFIG_SC_GPIO)		+= sc_gpio.o
+obj-$(CONFIG_SC_ACB)		+= sc_acb.o
+obj-$(CONFIG_SC_PC8736X)	+= pc8736x.o
+obj-$(CONFIG_SC_SCX200)		+= scx.o
+
+superio-objs		:= sc.o chain.o sc_conn.o
diff -Nru a/drivers/superio/chain.c b/drivers/superio/chain.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/chain.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,52 @@
+/*
+ * 	chain.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "chain.h"
+
+struct dev_chain *chain_alloc(void *ptr)
+{
+	struct dev_chain *ch;
+
+	ch = kmalloc(sizeof(struct dev_chain), GFP_ATOMIC);
+	if (!ch) {
+		printk(KERN_ERR "Failed to allocate new chain for %p.\n", ptr);
+		return NULL;
+	}
+
+	memset(ch, 0, sizeof(struct dev_chain));
+
+	ch->ptr = ptr;
+
+	return ch;
+}
+
+void chain_free(struct dev_chain *ch)
+{
+	memset(ch, 0, sizeof(struct dev_chain));
+	kfree(ch);
+}
diff -Nru a/drivers/superio/chain.h b/drivers/superio/chain.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/chain.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,37 @@
+/*
+ * 	chain.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __CHAIN_H
+#define __CHAIN_H
+
+#include <linux/list.h>
+
+struct dev_chain
+{
+	struct list_head	chain_entry;
+	void			*ptr;
+};
+
+struct dev_chain *chain_alloc(void *ptr);
+void chain_free(struct dev_chain *ch);
+
+#endif /* __CHAIN_H */
diff -Nru a/drivers/superio/pc8736x.c b/drivers/superio/pc8736x.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/pc8736x.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,209 @@
+/*
+ * 	pc8736x.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/suspend.h>
+
+#include "sc.h"
+#include "pc8736x.h"
+#include "sc_gpio.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for PC87366 SuperIO chip.");
+
+static int pc8736x_probe(void *, unsigned long base);
+static int pc8736x_activate_one_logical(struct logical_dev *ldev);
+static int pc8736x_deactivate_one_logical(struct logical_dev *ldev);
+
+static struct sc_dev pc8736x_dev = {
+	.name = 		"PC8736X",
+	.probe =		pc8736x_probe,
+	.activate_one =		pc8736x_activate_one_logical,
+	.deactivate_one = 	pc8736x_deactivate_one_logical,
+	//.read = 		pc8736x_read,
+	//.write = 		pc8736x_write,
+};
+
+static struct sc_chip_id pc8736x_sio_ids[] = {
+	{"PC87360", 0xe1},
+	{"PC87363", 0xe8},
+	{"PC87364", 0xe4},
+	{"PC87365", 0xe5},
+	{"PC87366", 0xe9},
+};
+
+void pc8736x_write_reg(struct sc_dev *dev, u8 reg, u8 val)
+{
+	outb(reg, dev->base_index);
+	outb(val, dev->base_data);
+}
+
+u8 pc8736x_read_reg(struct sc_dev *dev, u8 reg)
+{
+	u8 val;
+
+	outb(reg, dev->base_index);
+	val = inb(dev->base_data);
+
+	return val;
+}
+
+static int pc8736x_chip_index(u8 id)
+{
+	int i;
+
+	for (i = 0; i < sizeof(pc8736x_sio_ids) / sizeof(pc8736x_sio_ids[0]); ++i)
+		if (pc8736x_sio_ids[i].id == id)
+			return i;
+
+	return -ENODEV;
+}
+
+static int pc8736x_probe(void *data, unsigned long base)
+{
+	unsigned long size = 2;
+	u8 id;
+	int chip_num;
+	struct sc_dev *dev = (struct sc_dev *)data;
+
+	/*
+	 * Special address to handle.
+	 */
+	if (base == 0)
+		return -ENODEV;
+
+	dev->base_index = base;
+	dev->base_data = base + 1;
+
+	id = pc8736x_read_reg(dev, SIO_REG_SID);
+	chip_num = pc8736x_chip_index(id);
+
+	if (chip_num >= 0) {
+		printk(KERN_INFO "Found %s [0x%x] at 0x%04lx-0x%04lx.\n",
+		       pc8736x_sio_ids[chip_num].name,
+		       pc8736x_sio_ids[chip_num].id, 
+		       base, base + size - 1);
+		return 0;
+	}
+
+	printk(KERN_INFO "Found nothing at 0x%04lx-0x%04lx.\n", 
+			base, base + size - 1);
+
+	return -ENODEV;
+}
+
+static int pc8736x_deactivate_one_logical(struct logical_dev *ldev)
+{
+	return 0;
+}
+
+static int pc8736x_activate_one_logical(struct logical_dev *ldev)
+{
+	int err;
+	struct sc_dev *dev = ldev->pdev;
+	u8 active;
+
+	pc8736x_write_reg(dev, SIO_REG_LDN, ldev->index);
+	active = pc8736x_read_reg(dev, SIO_REG_ACTIVE);
+	if ((active & SIO_ACTIVE_EN) == 0) {
+		printk(KERN_INFO "\t%16s - not activated at %x: activating... ",
+		       ldev->name, ldev->index);
+
+		pc8736x_write_reg(dev, SIO_REG_ACTIVE, active | SIO_ACTIVE_EN);
+		active = pc8736x_read_reg(dev, SIO_REG_ACTIVE);
+		if ((active & SIO_ACTIVE_EN) == 0) {
+			printk("failed.\n");
+			return -ENODEV;
+		}
+		printk("done\n");
+	}
+
+	pc8736x_write_reg(dev, SIO_REG_IRQ, ldev->irq);
+	ldev->irq = pc8736x_read_reg(dev, SIO_REG_IRQ);
+
+	ldev->irq_type = pc8736x_read_reg(dev, SIO_REG_IRQ_TYPE);
+	ldev->base_addr = pc8736x_read_reg(dev, SIO_REG_IO_LSB);
+	ldev->base_addr |= (pc8736x_read_reg(dev, SIO_REG_IO_MSB) << 8);
+
+	err = ldev->activate(ldev);
+	if (err < 0) {
+		printk(KERN_INFO "\t%16s - not activated: ->activate() failed with error code %d.\n",
+		       ldev->name, err);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "\t%16s - activated: 0x%04lx-0x%04lx, irq=%02x [type=%02x]\n",
+	       ldev->name, ldev->base_addr, ldev->base_addr + ldev->range,
+	       ldev->irq, ldev->irq_type);
+
+	return 0;
+}
+
+static int pc8736x_init(void)
+{
+	int err;
+
+	err = sc_add_sc_dev(&pc8736x_dev);
+	if (err)
+		return err;
+
+	printk(KERN_INFO "Driver for %s SuperIO chip.\n", pc8736x_dev.name);
+	return 0;
+}
+
+static void pc8736x_fini(void)
+{
+	sc_del_sc_dev(&pc8736x_dev);
+
+	while (atomic_read(&pc8736x_dev.refcnt)) {
+		printk(KERN_INFO "Waiting for %s to became free: refcnt=%d.\n",
+				pc8736x_dev.name, atomic_read(&pc8736x_dev.refcnt));
+
+		msleep_interruptible(1000);
+
+		if (signal_pending(current))
+			flush_signals(current);
+			
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+
+	}
+}
+
+module_init(pc8736x_init);
+module_exit(pc8736x_fini);
+
+EXPORT_SYMBOL(pc8736x_write_reg);
+EXPORT_SYMBOL(pc8736x_read_reg);
diff -Nru a/drivers/superio/pc8736x.h b/drivers/superio/pc8736x.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/pc8736x.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,39 @@
+/*
+ * 	pc8736x.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __PC8736X_H
+#define __PC8736X_H
+
+#define SIO_GPDO0		0x00
+#define SIO_GPDI0 		0x01
+#define SIO_GPEVEN0		0x02 
+#define SIO_GPEVST0		0x03 
+#define SIO_GPDO1 		0x04
+#define SIO_GPDI1 		0x05
+#define SIO_GPEVEN1		0x06 
+#define SIO_GPEVST1		0x07 
+#define SIO_GPDO2 		0x08
+#define SIO_GPDI2 		0x09
+#define SIO_GPDO3 		0x0A
+#define SIO_GPDI3 		0x0B
+
+#endif /* __PC8736X_H */
diff -Nru a/drivers/superio/pin_test.c b/drivers/superio/pin_test.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/pin_test.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,93 @@
+/*
+ * 	pin_test.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include "sc.h"
+#include "sc_gpio.h"
+
+MODULE_LICENSE ("GPL");
+
+static int test_pin = 21;
+module_param(test_pin, int, 0);
+
+static struct timer_list tm;
+static struct logical_dev *ldev;
+
+static void tm_func(unsigned long data)
+{
+	int i;
+	int val;
+
+	for (i=0; i<SIO_GPIO_NPINS; ++i)
+	{
+		val = ldev->read(ldev, i);
+		printk("%02d.%d ", i, val);
+		if (i % 8 == 7)
+			printk("\n");
+
+		if (i == test_pin)
+			ldev->write(ldev, i, (val)?0:1);
+	}
+	printk("\n");
+
+	mod_timer(&tm, jiffies + HZ);
+}
+
+int __devinit tm_init (void)
+{
+	int i;
+	
+	ldev = sc_get_ldev("GPIO");
+	if (!ldev)
+	{
+		printk(KERN_ERR "Logical device GPIO is not registered.\n");
+		return -ENODEV;
+	}
+	for (i=0; i<SIO_GPIO_NPINS; ++i)
+		ldev->control(ldev, i, ~0, SIO_GPIO_CONF_PUSHPULL);
+
+	init_timer(&tm);
+	tm.expires = jiffies + HZ;
+	tm.function = tm_func;
+	tm.data = 0;
+	add_timer(&tm);
+
+	return 0;
+}
+
+void __devexit tm_fini(void)
+{
+	del_timer_sync(&tm);
+	sc_put_ldev(ldev);
+}
+
+module_init(tm_init);
+module_exit(tm_fini);
diff -Nru a/drivers/superio/sc.c b/drivers/superio/sc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,802 @@
+/*
+ * 	sc.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+
+#include "sc.h"
+#include <linux/sc_conn.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Generic SuperIO driver.");
+
+static unsigned long base_addr[] = { 0x2e, 0x4e };
+
+static spinlock_t sdev_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(sdev_list);
+
+static spinlock_t ldev_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(ldev_list);
+
+static int sc_activate_logical(struct sc_dev *, struct logical_dev *);
+static void sc_deactivate_logical(struct sc_dev *, struct logical_dev *);
+
+static int __devinit sc_init(void);
+static void __devexit sc_fini(void);
+
+static inline int sc_ldev_equal(struct logical_dev *l1, struct logical_dev *l2)
+{
+	int a, b;
+
+	a = b = 1;
+
+	a = (!strncmp(l1->name, l2->name, SC_NAME_LEN) && l1->index == l2->index);
+
+	if (sc_ldev_is_clone(l1) && sc_ldev_is_clone(l2))
+		b = (l1->base_addr == l2->base_addr);
+
+	return (a && b);
+}
+
+static inline int sc_ldev_equal_name(struct logical_dev *l1,
+				     struct logical_dev *l2)
+{
+	return (!strncmp(l1->name, l2->name, SC_NAME_LEN));
+}
+
+static inline int sc_sdev_equal(struct sc_dev *s1, struct sc_dev *s2)
+{
+	return (!strncmp(s1->name, s2->name, SC_NAME_LEN));
+}
+
+static void sc_del_sdev_from_ldev(struct sc_dev *sdev, struct logical_dev *ldev)
+{
+	struct sc_dev *__sdev;
+	struct dev_chain *ch, *n;
+
+	spin_lock(&ldev->chain_lock);
+
+	list_for_each_entry_safe(ch, n, &ldev->chain_list, chain_entry) {
+		__sdev = ch->ptr;
+
+		if (sc_sdev_equal(__sdev, sdev)) {
+			list_del(&ch->chain_entry);
+			chain_free(ch);
+			smp_mb__before_atomic_dec();
+			atomic_dec(&__sdev->refcnt);
+			smp_mb__after_atomic_dec();
+			break;
+		}
+	}
+
+	spin_unlock(&ldev->chain_lock);
+}
+
+static int __sc_add_logical_dev(struct sc_dev *dev, struct logical_dev *__ldev)
+{
+	int err;
+	struct logical_dev *ldev;
+	struct dev_chain *ch, *lch, *_ch;
+	int __found = 0;
+
+	err = 0;
+
+	list_for_each_entry(_ch, &dev->chain_list, chain_entry) {
+		ldev = _ch->ptr;
+
+		if (sc_ldev_equal(ldev, __ldev)) {
+			printk(KERN_INFO "Logical device %s already registered in SuperIO chip %s.\n",
+			       ldev->name, dev->name);
+			err++;
+			break;
+		}
+	}
+
+	if (err) {
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	if (!sc_ldev_is_clone(__ldev)) {
+		struct sc_chip_id *cid;
+
+		/*
+		 * SuperIO core is registering logical device. 
+		 * SuperIO chip knows where it must live.
+		 * If logical device being registered lives at the different location
+		 * (for example when it was registered for all devices, 
+		 * but has address(index) corresponding to only one SuperIO chip) 
+		 * then we will register new logical device with the same name 
+		 * but with the different location(index).
+		 *
+		 * It is called clone.
+		 */
+
+		for (cid = dev->ldevs; cid && strlen(cid->name); ++cid) {
+			if (!strncmp(cid->name, __ldev->name, SC_NAME_LEN)
+			    && cid->id != __ldev->index) {
+				struct logical_dev *clone;
+
+				__found = 1;
+
+				printk(KERN_INFO "Logical device %s in chip %s lives at %x, but provided address %x.\n"
+				       "Registering new logical device %s in chip %s with address %x.\n",
+				       __ldev->name, dev->name, cid->id,
+				       __ldev->index, __ldev->name, dev->name,
+				       cid->id);
+
+				clone = sc_ldev_clone(__ldev);
+				if (!clone) {
+					err = -ENOMEM;
+					continue;
+				}
+
+				/*
+				 * If logical device provided 0xFF index, than it is mean that
+				 * SuperIO chip driver must handle this situation.
+				 * It is similar to the zero base address in SuperIO ->probe() function.
+				 */
+
+				clone->index = cid->id;
+
+				err = __sc_add_logical_dev(dev, clone);
+				if (err)
+					sc_ldev_unclone(clone);
+			}
+		}
+
+		if (__found)
+			return 0;
+	}
+
+	__ldev->pdev = dev;
+	err = sc_activate_logical(dev, __ldev);
+	if (err) {
+		printk(KERN_INFO "Logical device %s is not found in SuperIO chip %s.\n",
+		       __ldev->name, dev->name);
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	ch = chain_alloc(dev);
+	if (!ch) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	lch = chain_alloc(__ldev);
+	if (!lch) {
+		err = -ENOMEM;
+		goto err_out_free_chain;
+	}
+
+	ch->ptr = dev;
+
+	spin_lock(&__ldev->chain_lock);
+	smp_mb__before_atomic_inc();
+	atomic_inc(&__ldev->refcnt);
+	smp_mb__after_atomic_inc();
+	list_add_tail(&ch->chain_entry, &__ldev->chain_list);
+	spin_unlock(&__ldev->chain_lock);
+
+	smp_mb__before_atomic_inc();
+	atomic_inc(&dev->refcnt);
+	smp_mb__after_atomic_inc();
+	list_add_tail(&lch->chain_entry, &dev->chain_list);
+
+	__found = 0;
+	spin_lock(&ldev_lock);
+	list_for_each_entry(ldev, &ldev_list, ldev_entry) {
+		if (sc_ldev_equal(ldev, __ldev)) {
+			__found = 1;
+			break;
+		}
+	}
+
+	if (!__found) {
+		list_add(&__ldev->ldev_entry, &ldev_list);
+	}
+
+	spin_unlock(&ldev_lock);
+
+	return 0;
+
+	chain_free(lch);
+err_out_free_chain:
+	chain_free(ch);
+err_out:
+
+	return err;
+}
+
+int sc_add_logical_dev(struct sc_dev *sdev, struct logical_dev *__ldev)
+{
+	struct sc_dev *dev;
+	int err, found = 0;
+
+	printk(KERN_INFO "Adding logical device %s [%x] [%s].\n",
+	       __ldev->name, __ldev->index,
+	       (sc_ldev_is_clone(__ldev)) ? "clone" : "not clone");
+
+	spin_lock_init(&__ldev->chain_lock);
+	INIT_LIST_HEAD(&__ldev->chain_list);
+
+	spin_lock_init(&__ldev->lock);
+
+	atomic_set(&__ldev->refcnt, 0);
+
+	if (sdev) {
+		spin_lock(&sdev->lock);
+		spin_lock(&sdev->chain_lock);
+		err = __sc_add_logical_dev(sdev, __ldev);
+		spin_unlock(&sdev->chain_lock);
+		spin_unlock(&sdev->lock);
+
+		if (!err)
+			found = 1;
+
+		goto finish;
+	}
+
+	spin_lock(&sdev_lock);
+	list_for_each_entry(dev, &sdev_list, sdev_entry) {
+		spin_lock(&dev->lock);
+		spin_lock(&dev->chain_lock);
+		err = __sc_add_logical_dev(dev, __ldev);
+		spin_unlock(&dev->chain_lock);
+		spin_unlock(&dev->lock);
+		if (!err)
+			found = 1;
+	}
+	spin_unlock(&sdev_lock);
+
+finish:
+
+	return (found) ? 0 : -ENODEV;
+}
+
+/*
+ * Must be called under ldev->chain_lock and ldev_lock held.
+ */
+static void __sc_del_logical_dev(struct sc_dev *dev, struct logical_dev *__ldev)
+{
+	struct dev_chain *ch, *n;
+	struct logical_dev *ldev;
+
+	spin_lock(&dev->chain_lock);
+	list_for_each_entry_safe(ch, n, &dev->chain_list, chain_entry) {
+		ldev = ch->ptr;
+
+		if (sc_ldev_equal(ldev, __ldev)) {
+			list_del(&ch->chain_entry);
+			smp_mb__before_atomic_dec();
+			atomic_dec(&ldev->refcnt);
+			smp_mb__after_atomic_dec();
+			chain_free(ch);
+
+			sc_deactivate_logical(dev, ldev);
+
+			break;
+		}
+	}
+	spin_unlock(&dev->chain_lock);
+}
+
+void sc_del_logical_dev(struct logical_dev *ldev)
+{
+	struct sc_dev *dev;
+	struct dev_chain *ch, *n;
+	struct logical_dev *ld, *ln;
+
+	spin_lock(&ldev->lock);
+
+	spin_lock(&ldev->chain_lock);
+	list_for_each_entry_safe(ch, n, &ldev->chain_list, chain_entry) {
+		dev = ch->ptr;
+
+		spin_lock(&dev->lock);
+		printk(KERN_INFO "Deactivating %s [%s/%s] from %s\n",
+		       ldev->name,
+		       (sc_ldev_is_clone(ldev)) ? "clone" : "not clone",
+		       (sc_ldev_cloned(ldev)) ? "cloned" : "not cloned",
+		       dev->name);
+		__sc_del_logical_dev(dev, ldev);
+
+		list_del(&ch->chain_entry);
+		smp_mb__before_atomic_dec();
+		atomic_dec(&dev->refcnt);
+		smp_mb__after_atomic_dec();
+		chain_free(ch);
+		spin_unlock(&dev->lock);
+	}
+	spin_unlock(&ldev->chain_lock);
+
+	if (sc_ldev_is_clone(ldev)) {
+		spin_unlock(&ldev->lock);
+		return;
+	}
+
+	spin_lock(&ldev_lock);
+	list_for_each_entry_safe(ld, ln, &ldev_list, ldev_entry) {
+		printk(KERN_INFO "Processing ldev %s [%s/%s] [%x]\n",
+		       ld->name,
+		       (sc_ldev_is_clone(ld)) ? "clone" : "not clone",
+		       (sc_ldev_cloned(ld)) ? "cloned" : "not cloned",
+		       ld->index);
+		if (sc_ldev_equal(ld, ldev)) {
+			list_del(&ld->ldev_entry);
+		} else if (sc_ldev_cloned(ldev)) {
+			/*
+			 * When logical device is clonned 
+			 * clone's chunks can point to the diferent device 
+			 * than origianl logical device's chunks.
+			 * Since we do not have backlink from the original device
+			 * to it's clones we must run through the whole ldev_list.
+			 */
+
+			if (sc_ldev_is_clone(ld) && sc_ldev_equal_name(ld, ldev)) {
+				list_del(&ld->ldev_entry);
+				sc_del_logical_dev(ld);
+				sc_ldev_unclone(ld);
+			}
+		}
+	}
+	spin_unlock(&ldev_lock);
+
+	spin_unlock(&ldev->lock);
+
+	while (atomic_read(&ldev->refcnt)) {
+		printk(KERN_INFO "Waiting logical device %s [%x] [%s] to become free: refcnt=%d.\n",
+		       ldev->name, ldev->index,
+		       (sc_ldev_is_clone(ldev)) ? "clone" : "not clone",
+		       atomic_read(&ldev->refcnt));
+
+		msleep_interruptible(1000);
+
+		if (signal_pending(current))
+			flush_signals(current);
+			
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+	}
+
+}
+
+static int sc_check_sc_dev(struct sc_dev *dev)
+{
+	if (!dev->activate_one) {
+		printk(KERN_ERR "SuperIO device %s does not have ->activate_one() method.\n",
+		       dev->name);
+		return -EINVAL;
+	}
+
+	if (!dev->probe) {
+		printk(KERN_ERR "SuperIO device %s does not have ->probe() method.\n",
+		       dev->name);
+		return -EINVAL;
+	}
+
+	if (!dev->ldevs)
+		printk(KERN_INFO "SuperIO device %s does not have logical device table.\n",
+		       dev->name);
+
+	return 0;
+}
+
+int sc_add_sc_dev(struct sc_dev *__sdev)
+{
+	int i, err;
+	struct sc_dev *sdev;
+
+	if (sc_check_sc_dev(__sdev))
+		return -EINVAL;
+
+	spin_lock_init(&__sdev->chain_lock);
+	INIT_LIST_HEAD(&__sdev->chain_list);
+
+	spin_lock_init(&__sdev->lock);
+
+	spin_lock(&sdev_lock);
+	list_for_each_entry(sdev, &sdev_list, sdev_entry) {
+		if (sc_sdev_equal(sdev, __sdev)) {
+			printk(KERN_INFO "Super IO chip %s already registered.\n",
+			       sdev->name);
+			spin_unlock(&sdev_lock);
+			return -EINVAL;
+		}
+	}
+
+	err = -ENODEV;
+	for (i = 0; i < sizeof(base_addr) / sizeof(base_addr[0]); ++i) {
+		err = __sdev->probe(__sdev, base_addr[i]);
+		if (!err)
+			break;
+	}
+
+	/*
+	 * Special case for non standard base location.
+	 */
+	if (i == sizeof(base_addr) / sizeof(base_addr[0]))
+		err = __sdev->probe(__sdev, 0);
+
+	if (!err) {
+		atomic_set(&__sdev->refcnt, 0);
+		list_add_tail(&__sdev->sdev_entry, &sdev_list);
+	}
+
+	spin_unlock(&sdev_lock);
+
+	return err;
+}
+
+void sc_del_sc_dev(struct sc_dev *__sdev)
+{
+	struct dev_chain *ch, *n;
+	struct logical_dev *ldev;
+	struct sc_dev *sdev, *sn;
+
+	spin_lock(&__sdev->lock);
+	spin_lock(&sdev_lock);
+	list_for_each_entry_safe(sdev, sn, &sdev_list, sdev_entry) {
+		if (sc_sdev_equal(sdev, __sdev)) {
+			list_del(&sdev->sdev_entry);
+			break;
+		}
+	}
+	spin_unlock(&sdev_lock);
+
+	spin_lock(&__sdev->chain_lock);
+	list_for_each_entry_safe(ch, n, &__sdev->chain_list, chain_entry) {
+		ldev = ch->ptr;
+
+		list_del(&ch->chain_entry);
+		smp_mb__before_atomic_dec();
+		atomic_dec(&ldev->refcnt);
+		smp_mb__after_atomic_dec();
+		chain_free(ch);
+
+		sc_deactivate_logical(__sdev, ldev);
+		sc_del_sdev_from_ldev(__sdev, ldev);
+	}
+	spin_unlock(&__sdev->chain_lock);
+	spin_unlock(&__sdev->lock);
+
+	while (atomic_read(&__sdev->refcnt)) {
+		printk(KERN_INFO "Waiting SuperIO chip %s to become free: refcnt=%d.\n",
+		       __sdev->name, atomic_read(&__sdev->refcnt));
+
+		msleep_interruptible(1000);
+
+		if (signal_pending(current))
+			flush_signals(current);
+			
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+	}
+}
+
+static void sc_deactivate_logical(struct sc_dev *dev, struct logical_dev *ldev)
+{
+	printk(KERN_INFO "Deactivating logical device %s in SuperIO chip %s... ",
+	       ldev->name, dev->name);
+	
+	if (ldev->irq)
+	{
+		free_irq(ldev->irq, ldev);
+		ldev->irq = 0;
+	}
+
+
+	if (dev->deactivate_one)
+		dev->deactivate_one(ldev);
+
+	printk("done.\n");
+}
+
+/*
+ * Must be called under sdev_lock held.
+ */
+static int sc_activate_logical(struct sc_dev *dev, struct logical_dev *ldev)
+{
+	int err;
+
+	printk(KERN_INFO "Activating logical device %s [%x].\n", ldev->name,
+	       ldev->index);
+
+	if (ldev->irq && !ldev->irq_handler)
+		ldev->irq = 0;
+
+	ldev->pdev = dev;
+	err = dev->activate_one(ldev);
+	if (err)
+		return err;
+	
+	if (ldev->irq)
+	{
+		err = request_irq(ldev->irq, ldev->irq_handler, SA_SHIRQ | SA_INTERRUPT, ldev->name, ldev);
+		if (err)
+		{
+			printk(KERN_ERR "Failed to request irq %d: err=%d. Disabling interrupt.\n", 
+					ldev->irq, err);
+			ldev->irq = 0;
+		}
+	}
+		
+
+	
+	return err;
+}
+
+struct sc_dev *sc_get_sdev(char *name)
+{
+	struct sc_dev *sdev;
+
+	spin_lock(&sdev_lock);
+	list_for_each_entry(sdev, &sdev_list, sdev_entry) {
+		if (!strcmp(name, sdev->name)) {
+			atomic_inc(&sdev->refcnt);
+			smp_mb__after_atomic_inc();
+			spin_unlock(&sdev_lock);
+			return sdev;
+		}
+	}
+	spin_unlock(&sdev_lock);
+
+	return NULL;
+}
+
+void sc_put_sdev(struct sc_dev *sdev)
+{
+	smp_mb__before_atomic_dec();
+	atomic_dec(&sdev->refcnt);
+	smp_mb__after_atomic_dec();
+}
+
+/*
+ * Get logical device which has given name and index.
+ */
+struct logical_dev *sc_get_ldev_index(char *name, u8 index)
+{
+	struct logical_dev *ldev;
+
+	spin_lock(&ldev_lock);
+	list_for_each_entry(ldev, &ldev_list, ldev_entry) {
+		if (!strcmp(name, ldev->name) && ldev->index == index) {
+			atomic_inc(&ldev->refcnt);
+			smp_mb__after_atomic_inc();
+			spin_unlock(&ldev_lock);
+			return ldev;
+		}
+	}
+	spin_unlock(&ldev_lock);
+
+	return NULL;
+}
+
+/*
+ * Get the first logical device with the given name.
+ */
+struct logical_dev *sc_get_ldev(char *name)
+{
+	struct logical_dev *ldev;
+
+	spin_lock(&ldev_lock);
+	list_for_each_entry(ldev, &ldev_list, ldev_entry) {
+		if (!strcmp(name, ldev->name)) {
+			atomic_inc(&ldev->refcnt);
+			smp_mb__after_atomic_inc();
+			spin_unlock(&ldev_lock);
+			return ldev;
+		}
+	}
+	spin_unlock(&ldev_lock);
+
+	return NULL;
+}
+
+/*
+ * Get the first logical device with the given name connected to given SuperIO chip.
+ */
+struct logical_dev *sc_get_ldev_in_sdev(char *name, struct sc_dev *sdev)
+{
+	struct dev_chain *ch;
+	struct logical_dev *ldev;
+
+	spin_lock(&sdev->chain_lock);
+	list_for_each_entry(ch, &sdev->chain_list, chain_entry) {
+		ldev = ch->ptr;
+
+		if (!strcmp(name, ldev->name)) {
+			atomic_inc(&ldev->refcnt);
+			smp_mb__after_atomic_inc();
+			spin_unlock(&sdev->chain_lock);
+			return ldev;
+		}
+	}
+	spin_unlock(&sdev->chain_lock);
+
+	return NULL;
+}
+
+void sc_put_ldev(struct logical_dev *ldev)
+{
+	smp_mb__before_atomic_dec();
+	atomic_dec(&ldev->refcnt);
+	smp_mb__after_atomic_dec();
+}
+
+/*
+ * Cloned logical device has the same structure as original device.
+ * Although cloned and original devices do not cross, they both point
+ * to the same block of the memory(they have pointers to the same functions), 
+ * so we will increment reference counter for original device 
+ * like cloned device has a reference to it.
+ */
+struct logical_dev *sc_ldev_clone(struct logical_dev *ldev)
+{
+	struct logical_dev *__ldev;
+
+	__ldev = sc_ldev_alloc(ldev->name, ldev->index);
+	if (!__ldev)
+		return NULL;
+
+	memcpy(__ldev, ldev, sizeof(*__ldev));
+
+	spin_lock_init(&__ldev->chain_lock);
+	INIT_LIST_HEAD(&__ldev->chain_list);
+	spin_lock_init(&__ldev->lock);
+
+	atomic_inc(&ldev->refcnt);
+	smp_mb__after_atomic_inc();
+	set_bit(LDEV_CLONED, (long *)&ldev->flags);
+
+	atomic_set(&__ldev->refcnt, 0);
+	__ldev->orig_ldev = ldev;
+
+	return __ldev;
+}
+
+int sc_ldev_is_clone(struct logical_dev *ldev)
+{
+	return (ldev->orig_ldev) ? 1 : 0;
+}
+
+int sc_ldev_cloned(struct logical_dev *ldev)
+{
+	return (test_bit(LDEV_CLONED, (long *)&ldev->flags)
+		&& (atomic_read(&ldev->refcnt) >= 1));
+}
+
+void sc_ldev_unclone(struct logical_dev *clone)
+{
+	struct logical_dev *orig = clone->orig_ldev;
+
+	if (!sc_ldev_is_clone(clone)) {
+		printk(KERN_INFO "Logical device %s is not clone.\n",
+		       clone->name);
+		return;
+	}
+
+	if (atomic_dec_and_test(&orig->refcnt))
+		clear_bit(LDEV_CLONED, (long *)&orig->flags);
+
+	memset(clone, 0, sizeof(*clone));
+	kfree(clone);
+	clone = NULL;
+}
+
+struct logical_dev *sc_ldev_alloc(char *name, u8 index)
+{
+	struct logical_dev *ldev;
+
+	ldev = kmalloc(sizeof(*ldev), GFP_ATOMIC);
+	if (!ldev) {
+		printk(KERN_ERR "Failed to allocate new logical device %s at address %x.\n",
+		       name, index);
+		return NULL;
+	}
+
+	memset(ldev, 0, sizeof(*ldev));
+
+	snprintf(ldev->name, sizeof(ldev->name), "%s", name);
+	ldev->index = index;
+
+	return ldev;
+}
+
+void sc_ldev_free(struct logical_dev *ldev)
+{
+	if (ldev->orig_ldev) {
+		struct logical_dev *orig = ldev->orig_ldev;
+		/*
+		 * It is clone.
+		 */
+		if (!atomic_dec_and_test(&ldev->refcnt)) {
+			/*
+			 * It is impossible, clone can not have clones.
+			 */
+			printk(KERN_INFO "Logical device clone %s has refcnt=%d and flags=%x.\n",
+			       ldev->name, atomic_read(&ldev->refcnt),
+			       ldev->flags);
+			BUG();
+		}
+
+		spin_lock(&orig->lock);
+
+		clear_bit(LDEV_CLONED, (long *)&orig->flags);
+		smp_mb__before_atomic_dec();
+		atomic_dec(&orig->refcnt);
+		smp_mb__after_atomic_dec();
+
+		memset(ldev, 0, sizeof(*ldev));
+		kfree(ldev);
+
+		spin_unlock(&orig->lock);
+	} else if (sc_ldev_cloned(ldev)) {
+		/*
+		 * It is cloned.
+		 */
+	}
+}
+
+static int __devinit sc_init(void)
+{
+	printk(KERN_INFO "SuperIO driver is starting...\n");
+
+	return sc_register_callback();
+}
+
+static void __devexit sc_fini(void)
+{
+	sc_unregister_callback();
+	printk(KERN_INFO "SuperIO driver finished.\n");
+}
+
+module_init(sc_init);
+module_exit(sc_fini);
+
+EXPORT_SYMBOL(sc_add_logical_dev);
+EXPORT_SYMBOL(sc_del_logical_dev);
+EXPORT_SYMBOL(sc_get_ldev);
+EXPORT_SYMBOL(sc_get_ldev_in_sdev);
+EXPORT_SYMBOL(sc_put_ldev);
+EXPORT_SYMBOL(sc_add_sc_dev);
+EXPORT_SYMBOL(sc_del_sc_dev);
+EXPORT_SYMBOL(sc_get_sdev);
+EXPORT_SYMBOL(sc_put_sdev);
+EXPORT_SYMBOL(sc_ldev_alloc);
+EXPORT_SYMBOL(sc_ldev_free);
+EXPORT_SYMBOL(sc_ldev_clone);
+EXPORT_SYMBOL(sc_ldev_unclone);
+EXPORT_SYMBOL(sc_ldev_cloned);
+EXPORT_SYMBOL(sc_ldev_is_clone);
diff -Nru a/drivers/superio/sc.h b/drivers/superio/sc.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,134 @@
+/*
+ * 	sc.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __SC_H
+#define __SC_H
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+#include "chain.h"
+
+#define SC_NAME_LEN		16
+
+#define SIO_REG_SID		0x20	/* Super I/O ID */
+
+#define SIO_REG_SRID		0x27	/* Super I/O Revision */
+#define SIO_REG_IRQ		0x70	/* IRQ number */
+#define SIO_REG_IRQ_TYPE	0x71	/* IRQ type */
+
+#define SIO_REG_LDN		0x07	/* Logical Device Number */
+#define SIO_LDN_GPIO		0x07	/* General-Purpose I/O (GPIO) Ports */
+#define SIO_LDN_ACB		0x08	/* Access bus */
+
+#define SIO_REG_ACTIVE		0x30	/* Logical Device Activate Register */
+#define SIO_ACTIVE_EN		0x01	/* enabled */
+#define SIO_RESET		0x02
+
+#define SIO_REG_IO_MSB		0x60	/* I/O Port Base, bits 15-8 */
+#define SIO_REG_IO_LSB		0x61	/* I/O Port Base, bits 7-0 */
+
+#define LDEV_PRIVATE		0xff	/* Logical device has non standard dynamic address (like PCI space) */
+
+#define LDEV_CLONED		(1<<0)
+
+struct logical_dev
+{
+	struct list_head	ldev_entry;
+
+	atomic_t		refcnt;
+	spinlock_t		lock;
+
+	struct list_head	chain_list;
+	spinlock_t		chain_lock;
+
+	unsigned char		name[SC_NAME_LEN];
+	u8			index;
+	
+	unsigned long		base_addr;
+	unsigned long		range;
+
+	u32			flags;
+
+	void			*pdev;
+	void			*orig_ldev;
+
+	u8			irq;
+	u8			irq_type;
+
+	int			(*activate)(void *);
+	u8			(*read)(void *, int);
+	void			(*write)(void *, int, u8);
+	void			(*control)(void *, int, u8, u8);
+	irqreturn_t		(*irq_handler)(int, void *, struct pt_regs *);
+};
+
+struct sc_dev
+{
+	struct list_head	sdev_entry;
+
+	atomic_t		refcnt;
+	spinlock_t		lock;
+	
+	struct list_head	chain_list;
+	spinlock_t		chain_lock;
+
+	unsigned char		name[SC_NAME_LEN];
+
+	void			*pdev;
+	unsigned long		base_index, base_data;
+
+	struct sc_chip_id	*ldevs;
+
+	int			(*probe)(void *, unsigned long);
+	int			(*activate_one)(struct logical_dev *);
+	int			(*deactivate_one)(struct logical_dev *);
+	u8			(*read)(struct logical_dev *, unsigned long);
+	void			(*write)(struct logical_dev *, unsigned long, u8);
+};
+
+struct sc_chip_id
+{
+	unsigned char		name[SC_NAME_LEN];
+	u8			id;
+};
+
+int sc_add_logical_dev(struct sc_dev *, struct logical_dev *);
+void sc_del_logical_dev(struct logical_dev *);
+struct logical_dev *sc_get_ldev(char *);
+struct logical_dev *sc_get_ldev_in_sdev(char *, struct sc_dev *);
+void sc_put_ldev(struct logical_dev *);
+
+int sc_add_sc_dev(struct sc_dev *);
+void sc_del_sc_dev(struct sc_dev *);
+struct sc_dev *sc_get_sdev(char *);
+void sc_put_sdev(struct sc_dev *);
+
+struct logical_dev *sc_ldev_clone(struct logical_dev *ldev);
+void sc_ldev_unclone(struct logical_dev *ldev);
+int sc_ldev_cloned(struct logical_dev *ldev);
+int sc_ldev_is_clone(struct logical_dev *ldev);
+
+struct logical_dev *sc_ldev_alloc(char *name, u8 index);
+void sc_ldev_free(struct logical_dev *ldev);
+
+#endif /* __SC_H */
diff -Nru a/drivers/superio/sc_acb.c b/drivers/superio/sc_acb.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc_acb.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,158 @@
+/*
+ * 	sc_acb.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include "sc.h"
+#include "sc_acb.h"
+
+static int sc_acb_activate(void *data);
+static u8 sc_acb_read(void *data, int reg);
+static void sc_acb_write(void *data, int reg, u8 byte);
+static void sc_acb_control(void *data, int pin, u8 mask, u8 ctl);
+
+static struct logical_dev ldev_acb = {
+	.name = "ACB",
+	.index = 0x08,
+	.range = 16,
+
+	.activate = sc_acb_activate,
+	.read = sc_acb_read,
+	.write = sc_acb_write,
+	.control = sc_acb_control,
+
+	.flags = 0,
+	.orig_ldev = NULL,
+};
+
+static void sc_write_reg(struct sc_dev *dev, u8 reg, u8 val)
+{
+	outb(reg, dev->base_index);
+	outb(val, dev->base_data);
+}
+
+static u8 sc_read_reg(struct sc_dev *dev, u8 reg)
+{
+	u8 val;
+
+	outb(reg, dev->base_index);
+	val = inb(dev->base_data);
+
+	return val;
+}
+
+static int sc_acb_activate(void *data)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	u8 val;
+
+	sc_write_reg(ldev->pdev, ACBCTL2, 1);
+
+	val = sc_read_reg(ldev->pdev, ACBCTL2);
+	if ((val & 1) != 1) {
+		printk(KERN_ERR "Can not enable %s at %x: ctl2=%x.\n",
+		       ldev->name, ldev->index, val);
+		return -ENODEV;
+	}
+
+	sc_write_reg(ldev->pdev, ACBCTL2, 0x71);
+
+	val = sc_read_reg(ldev->pdev, ACBCTL2);
+	if (val != 0x71) {
+		printk(KERN_ERR "ACBCTL2 readback failed: val=%x.\n", val);
+		return -ENXIO;
+	}
+
+	sc_write_reg(ldev->pdev, ACBCTL1,
+		     sc_read_reg(ldev->pdev, ACBCTL1) | ACBCTL1_NMINTE);
+
+	val = sc_read_reg(ldev->pdev, ACBCTL1);
+	if (val) {
+		printk(KERN_ERR "Disabled, but ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	sc_write_reg(ldev->pdev, ACBCTL2,
+		     sc_read_reg(ldev->pdev, ACBCTL2) | ACBCTL2_ENABLE);
+
+	sc_write_reg(ldev->pdev, ACBCTL1,
+		     sc_read_reg(ldev->pdev, ACBCTL1) | ACBCTL1_NMINTE);
+
+	val = sc_read_reg(ldev->pdev, ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		printk(KERN_ERR "Enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n",
+		       val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static u8 sc_acb_read(void *data, int reg)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	u8 val;
+
+	val = inb(ldev->base_addr + reg);
+
+	//printk("R: %02x\n", val);
+
+	return val;
+}
+
+static void sc_acb_write(void *data, int reg, u8 byte)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+
+	//printk("W: %02x\n", val);
+
+	outb(byte, ldev->base_addr + reg);
+}
+
+static void sc_acb_control(void *data, int pin, u8 mask, u8 ctl)
+{
+}
+
+static int __devinit sc_acb_init(void)
+{
+	printk(KERN_INFO "Access Bus logical device driver is activating now.\n");
+	INIT_LIST_HEAD(&ldev_acb.ldev_entry);
+	spin_lock_init(&ldev_acb.lock);
+	return sc_add_logical_dev(NULL, &ldev_acb);
+}
+
+static void __devexit sc_acb_fini(void)
+{
+	sc_del_logical_dev(&ldev_acb);
+	printk(KERN_INFO "Access Bus logical device driver finished.\n");
+}
+
+module_init(sc_acb_init);
+module_exit(sc_acb_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for Access Bus logical device.");
diff -Nru a/drivers/superio/sc_acb.h b/drivers/superio/sc_acb.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc_acb.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,45 @@
+/*
+ * 	sc_acb.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __SC_ACB_H
+#define __SC_ACB_H
+
+#define ACBSDA			(ldev->base_addr + 0)
+#define ACBST			(ldev->base_addr + 1)
+#define ACBST_SDAST		0x40 /* SDA Status */
+#define ACBST_BER		0x20 
+#define ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define ACBST_STASTR		0x08 /* Stall After Start */
+#define ACBST_MASTER		0x02
+#define ACBCST			(ldev->base_addr + 2)
+#define ACBCST_BB		0x02
+#define ACBCTL1		(ldev->base_addr + 3)
+#define ACBCTL1_STASTRE	0x80
+#define ACBCTL1_NMINTE		0x40
+#define ACBCTL1_ACK		0x10
+#define ACBCTL1_STOP		0x02
+#define ACBCTL1_START		0x01
+#define ACBADDR		(ldev->base_addr + 4)
+#define ACBCTL2		(ldev->base_addr + 5)
+#define ACBCTL2_ENABLE		0x01
+
+#endif /* __SC_ACB_H */
diff -Nru a/drivers/superio/sc_conn.c b/drivers/superio/sc_conn.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc_conn.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,124 @@
+/*
+ * 	sc_conn.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include <linux/connector.h>
+
+#include "sc.h"
+#include <linux/sc_conn.h>
+
+static struct cb_id sc_conn_id = { CN_IDX_SUPERIO, CN_VAL_SUPERIO };
+
+static void sc_conn_callback(void *data)
+{
+	struct cn_msg *reply, *msg = (struct cn_msg *)data;
+	struct sc_conn_data *rcmd, *cmd = (struct sc_conn_data *)(msg + 1);
+	struct logical_dev *ldev;
+	struct sc_dev *sdev;
+	u8 ret;
+
+	if (msg->len != sizeof(*cmd)) {
+		printk(KERN_ERR "Wrong additional data size %u, must be %u.\n",
+		       msg->len, sizeof(*cmd));
+		return;
+	}
+#if 0
+	printk
+	    ("%s: len=%u, seq=%u, ack=%u, sname=%s, lname=%s, idx=0x%x, cmd=%02x [%02x.%02x.%02x].\n",
+	     __func__, msg->len, msg->seq, msg->ack, cmd->sname, cmd->lname,
+	     cmd->idx, cmd->cmd, cmd->p0, cmd->p1, cmd->p2);
+#endif
+	sdev = sc_get_sdev(cmd->sname);
+	if (!sdev) {
+		printk(KERN_ERR "%s: sdev %s does not exist.\n", 
+			__func__, cmd->sname);
+		return;
+	}
+
+	ldev = sc_get_ldev_in_sdev(cmd->lname, sdev);
+	if (!ldev) {
+		printk(KERN_ERR "%s: ldev %s does not exist in chip %s.\n",
+		       __func__, cmd->lname, cmd->sname);
+		sc_put_sdev(sdev);
+		return;
+	}
+
+	ret = 0;
+	switch (cmd->cmd) {
+	case SC_CMD_LDEV_READ:
+		ret = ldev->read(ldev, cmd->p0);
+		reply = kmalloc(sizeof(*msg) + sizeof(*cmd), GFP_ATOMIC);
+		if (reply) {
+			memcpy(reply, msg, sizeof(*reply));
+
+			/*
+			 * See protocol description in connector.c
+			 */
+			reply->ack++;
+
+			rcmd = (struct sc_conn_data *)(reply + 1);
+			memcpy(rcmd, cmd, sizeof(*rcmd));
+
+			rcmd->cmd = SC_CMD_LDEV_READ;
+			rcmd->p0 = cmd->p0;
+			rcmd->p1 = ret;
+
+			cn_netlink_send(reply, 0);
+
+			kfree(reply);
+		} else
+			printk(KERN_ERR "Failed to allocate %d bytes in reply to comamnd 0x%x.\n",
+			       sizeof(*msg) + sizeof(*cmd), cmd->cmd);
+		break;
+	case SC_CMD_LDEV_WRITE:
+		ldev->write(ldev, cmd->p0, cmd->p1);
+		break;
+	case SC_CMD_LDEV_CONTROL:
+		ldev->control(ldev, cmd->p0, cmd->p1, cmd->p2);
+		break;
+	case SC_CMD_LDEV_ACTIVATE:
+		ldev->activate(ldev);
+		break;
+	default:
+		printk(KERN_ERR "Unsupported command 0x%x for %s in chip %s.\n",
+		       cmd->cmd, ldev->name, sdev->name);
+		break;
+	}
+
+	sc_put_ldev(ldev);
+	sc_put_sdev(sdev);
+}
+
+int sc_register_callback(void)
+{
+	return cn_add_callback(&sc_conn_id, "sc_callback",
+			       (void (*)(void *))&sc_conn_callback);
+}
+
+void sc_unregister_callback(void)
+{
+	return cn_del_callback(&sc_conn_id);
+}
+
+EXPORT_SYMBOL(sc_register_callback);
diff -Nru a/drivers/superio/sc_gpio.c b/drivers/superio/sc_gpio.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc_gpio.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,312 @@
+/*
+ * 	sc_gpio.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+
+#include "sc.h"
+#include "sc_gpio.h"
+#include "pc8736x.h"
+
+static struct gpio_pin gpin[SIO_GPIO_NPINS];
+
+static int sc_gpio_activate(void *);
+static u8 sc_gpio_read(void *, int);
+static void sc_gpio_write(void *, int, u8);
+static void sc_gpio_control(void *, int, u8, u8);
+static void sc_gpio_pin_select(void *, int);
+static irqreturn_t sc_gpio_interrupt(int, void *, struct pt_regs *);
+
+
+static struct logical_dev ldev_gpio = {
+	.name = "GPIO",
+	.index = SIO_LDN_GPIO,
+	.range = 16,
+
+	.activate 	= sc_gpio_activate,
+	.read 		= sc_gpio_read,
+	.write 		= sc_gpio_write,
+	.control 	= sc_gpio_control,
+	.irq_handler 	= sc_gpio_interrupt,
+
+	.irq		= 3,
+	
+	.flags = 0,
+	.orig_ldev = NULL,
+};
+
+static void sc_gpio_write_event(void *data, int pin_number, u8 byte);
+
+static void sc_write_reg(struct sc_dev *dev, u8 reg, u8 val)
+{
+	outb(reg, dev->base_index);
+	outb(val, dev->base_data);
+}
+
+static u8 sc_read_reg(struct sc_dev *dev, u8 reg)
+{
+	u8 val;
+
+	outb(reg, dev->base_index);
+	val = inb(dev->base_data);
+
+	return val;
+}
+
+static irqreturn_t sc_gpio_interrupt(int irq, void *data, struct pt_regs * regs)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	static u8 r[4], e[2], s[2];
+	u8 cr[4], ce[2], cs[2];
+	int i;
+
+	for (i=0; i<2; ++i)
+	{	
+		ce[i] = inb(ldev->base_addr + i*4 + 2);
+		cs[i] = inb(ldev->base_addr + i*4 + 3);
+	}
+	
+	for (i=0; i<4; ++i)
+		cr[i] = inb(ldev->base_addr + i*4 + 1);
+
+	for (i=0; i<4; ++i)
+	{
+		u8 p = cr[i] ^ r[i];
+		u8 f;
+		int pin, val;
+		
+		if (!p)
+			continue;
+		
+		while((f = ffs(p)))
+		{
+			f = ffs(p);
+			
+			pin = f + i*8 - 1;
+			val = ((cr[i] >> (f-1)) & 1);
+			printk("pin=%2d, val=%1d, jiffies=%lu\n", 
+					pin, val, jiffies);
+
+			p &= ~(1<<(f-1));
+		}
+
+
+		/*
+		 * Clear status byte.
+		 * Spec does not say that each IRQ shuld be ACKed, 
+		 * but it should.
+		 *
+		 * This is probably those ACK.
+		 */
+		outb(0xff, ldev->base_addr + i*4 + 3);
+	}
+		
+	memcpy(r, cr, sizeof(r));
+	memcpy(s, cs, sizeof(s));
+	memcpy(e, ce, sizeof(e));
+	
+	return IRQ_HANDLED;
+}
+
+
+static void sc_gpio_pin_select(void *data, int pin_number)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	int port, pin;
+	u8 val;
+
+	port = pin_number >> 3;
+	pin = pin_number - (pin_number & (~7));
+	val = (port << 4) | pin;
+
+	sc_write_reg(ldev->pdev, SIO_REG_LDN, SIO_LDN_GPIO);
+	sc_write_reg(ldev->pdev, SIO_GPIO_PINSEL, val);
+}
+
+static int sc_gpio_activate(void *data)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	int i;
+
+	memset(gpin, 0, sizeof(gpin));
+
+	for (i = 0; i < SIO_GPIO_NPINS; ++i) {
+		gpin[i].flags = SIO_GPIO_CONF_PULLUP | SIO_GPIO_CONF_EVENT_LEVEL;
+		gpin[i].mask &= ~(SIO_GPIO_CONF_DEBOUNCE);
+
+		sc_gpio_control(ldev, i, gpin[i].mask, gpin[i].flags);
+
+		gpin[i].state = GPIO_PIN_HIGH;
+		sc_gpio_write(ldev, i, gpin[i].state);
+
+		sc_gpio_write_event(ldev, i, 1);
+	}
+	
+	outb(0xff, ldev->base_addr + SIO_GPEVEN0);
+	outb(0xff, ldev->base_addr + SIO_GPEVEN1);
+
+	return 0;
+}
+
+static u8 sc_gpio_read(void *data, int pin_number)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	int port, pin;
+	u8 val, reg = SIO_GPDI0;
+
+	port = pin_number >> 3;
+	pin = pin_number - (pin_number & (~7));
+
+	switch (port) {
+	case 0:
+		reg = SIO_GPDI0;
+		break;
+	case 1:
+		reg = SIO_GPDI1;
+		break;
+	case 2:
+		reg = SIO_GPDI2;
+		break;
+	case 3:
+		reg = SIO_GPDI3;
+		break;
+	}
+
+	val = inb(ldev->base_addr + reg);
+
+	return ((val >> pin) & 0x01);
+}
+
+static void sc_gpio_write_event(void *data, int pin_number, u8 byte)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	int port, pin;
+	u8 val, reg = SIO_GPEVEN0;
+
+	port = pin_number >> 3;
+	pin = pin_number - (pin_number & (~7));
+
+	switch (port) {
+		case 0:
+			reg = SIO_GPEVEN0;
+			break;
+		case 1:
+			reg = SIO_GPEVEN1;
+			break;
+		default:
+			return;
+	}
+
+	val = inb(ldev->base_addr + reg);
+
+	if (byte)
+		val |= (1 << pin);
+	else
+		val &= ~(1 << pin);
+
+	outb(val, ldev->base_addr + reg);
+	
+	outb(1<<pin, ldev->base_addr + reg+1);
+}
+
+static void sc_gpio_write(void *data, int pin_number, u8 byte)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	int port, pin;
+	u8 val, reg = SIO_GPDO0, rreg = SIO_GPDI0;
+
+	port = pin_number >> 3;
+	pin = pin_number - (pin_number & (~7));
+
+	switch (port) {
+	case 0:
+		reg = SIO_GPDO0;
+		rreg = SIO_GPDI0;
+		break;
+	case 1:
+		reg = SIO_GPDO1;
+		rreg = SIO_GPDI1;
+		break;
+	case 2:
+		reg = SIO_GPDO2;
+		rreg = SIO_GPDI2;
+		break;
+	case 3:
+		reg = SIO_GPDO3;
+		rreg = SIO_GPDI3;
+		break;
+	}
+
+	//val = inb(ldev->base_addr + reg);
+	val = inb(ldev->base_addr + rreg);
+
+	if (byte)
+		val |= (1 << pin);
+	else
+		val &= ~(1 << pin);
+
+	//printk("W: %02x [%d]\n", val, ((val>>pin)&1));
+
+	outb(val, ldev->base_addr + reg);
+}
+
+static void sc_gpio_control(void *data, int pin, u8 mask, u8 ctl)
+{
+	struct logical_dev *ldev = (struct logical_dev *)data;
+	u8 cfg, ev;
+
+	sc_gpio_pin_select(ldev, pin);
+
+	cfg = sc_read_reg(ldev->pdev, SIO_GPIO_PINCFG);
+	ev = sc_read_reg(ldev->pdev, SIO_GPIO_PINEV);
+
+	cfg &= mask;
+	cfg |= ctl;
+
+	printk(KERN_INFO "pin=%2d cfg=%02x, mask=%02x, ctl=%02x, event=%02x\n", 
+			pin, cfg, mask, ctl, ev);
+	
+	sc_write_reg(ldev->pdev, SIO_GPIO_PINCFG, cfg);
+}
+
+static int __devinit sc_gpio_init(void)
+{
+	printk(KERN_INFO "GPIO logical device driver is activating now.\n");
+	INIT_LIST_HEAD(&ldev_gpio.ldev_entry);
+	spin_lock_init(&ldev_gpio.lock);
+	return sc_add_logical_dev(NULL, &ldev_gpio);
+}
+
+static void __devexit sc_gpio_fini(void)
+{
+	sc_del_logical_dev(&ldev_gpio);
+	printk(KERN_INFO "GPIO logical device driver finished.\n");
+}
+
+module_init(sc_gpio_init);
+module_exit(sc_gpio_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for GPIO logical device.");
diff -Nru a/drivers/superio/sc_gpio.h b/drivers/superio/sc_gpio.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc_gpio.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,50 @@
+/*
+ * 	sc_gpio.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __SC_GPIO_H
+#define __SC_GPIO_H
+
+#define SIO_GPIO_PINSEL		0xf0
+#define SIO_GPIO_PINCFG		0xf1
+#define SIO_GPIO_PINEV		0xf2
+
+#define GPIO_PIN_LOW		0x00	/* low level (logical 0) */
+#define GPIO_PIN_HIGH		0x01	/* high level (logical 1) */
+
+#define SIO_GPIO_NPINS		29
+
+#define SIO_GPIO_CONF_OUTPUTEN		(1 << 0)
+#define SIO_GPIO_CONF_PUSHPULL		(1 << 1)
+#define SIO_GPIO_CONF_PULLUP		(1 << 2)
+#define SIO_GPIO_CONF_LOCK		(1 << 3)
+#define SIO_GPIO_CONF_EVENT_LEVEL	(1 << 4)
+#define SIO_GPIO_CONF_EVENT_POLAR_RIS	(1 << 5)
+#define SIO_GPIO_CONF_DEBOUNCE		(1 << 6)
+
+struct gpio_pin
+{
+	u8			state;
+	u8			flags;
+	u8			mask;
+};
+
+#endif /* __SC_GPIO_H */
diff -Nru a/drivers/superio/sc_w1.c b/drivers/superio/sc_w1.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/sc_w1.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,107 @@
+/*
+ * 	sc_w1.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include "../w1/w1.h"
+#include "../w1/w1_int.h"
+#include "../w1/w1_log.h"
+
+#include "../superio/sc.h"
+#include "../superio/sc_gpio.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over SuperIO GPIO pins.");
+
+static int pin_number = 21;	/* Use pin 21 by default */
+module_param(pin_number, int, 0);
+
+struct sc_w1_device {
+	struct logical_dev *ldev;
+	struct w1_bus_master bus_master;
+} sc_w1;
+
+static u8 sc_w1_read_bit(unsigned long data)
+{
+	struct sc_w1_device *swd = (struct sc_w1_device *)data;
+
+	//swd->ldev->control(swd->ldev, pin_number, ~(SIO_GPIO_CONF_PUSHPULL | SIO_GPIO_CONF_PULLUP), 0);
+
+	return swd->ldev->read(swd->ldev, pin_number);
+}
+
+static void sc_w1_write_bit(unsigned long data, u8 bit)
+{
+	struct sc_w1_device *swd = (struct sc_w1_device *)data;
+	u8 mask = SIO_GPIO_CONF_OUTPUTEN;
+
+	swd->ldev->control(swd->ldev, pin_number, (bit)?~mask:~0, SIO_GPIO_CONF_PULLUP);
+	swd->ldev->write(swd->ldev, pin_number, bit);
+}
+
+int __devinit sc_w1_init(void)
+{
+	int err;
+
+	sc_w1.ldev = sc_get_ldev("GPIO");
+	if (!sc_w1.ldev) {
+		printk(KERN_ERR "Logical device GPIO is not registered.\n");
+		return -ENODEV;
+	}
+
+	sc_w1.bus_master.data = (unsigned long)&sc_w1;
+	sc_w1.bus_master.read_bit = sc_w1_read_bit;
+	sc_w1.bus_master.write_bit = sc_w1_write_bit;
+
+	err = w1_add_master_device(&sc_w1.bus_master);
+	if (err) {
+		printk(KERN_ERR "Failed to register sc_w1 master device: err=%d.\n",
+		       err);
+		sc_put_ldev(sc_w1.ldev);
+		return err;
+	}
+
+	printk(KERN_INFO "sc_w1 transport driver has been loaded. Pin number %d.\n",
+	       pin_number);
+
+	return 0;
+}
+
+void __devexit sc_w1_fini(void)
+{
+	w1_remove_master_device(&sc_w1.bus_master);
+
+	sc_put_ldev(sc_w1.ldev);
+
+	printk(KERN_INFO "sc_w1 transport driver has been unloaded.\n");
+}
+
+module_init(sc_w1_init);
+module_exit(sc_w1_fini);
diff -Nru a/drivers/superio/scx.c b/drivers/superio/scx.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/scx.c	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,413 @@
+/*
+ * 	scx.c
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pci.h>
+#include <linux/suspend.h>
+
+#include "sc.h"
+#include "scx.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for SCx200/SC1100 SuperIO chips.");
+
+static int scx200_probe(void *, unsigned long base);
+static int scx200_activate_one_logical(struct logical_dev *ldev);
+static int scx200_deactivate_one_logical(struct logical_dev *ldev);
+
+static struct sc_chip_id scx200_logical_devs[] = {
+	{"RTC", 0x00},
+	{"SWC", 0x01},
+	{"IRCP", 0x02},
+	{"ACB", 0x05},
+	{"ACB", 0x06},
+	{"SPORT", 0x08},
+	{"GPIO", LDEV_PRIVATE},
+	{}
+};
+
+static struct sc_dev scx200_dev = {
+	.name =			"SCx200",
+	.probe =		scx200_probe,
+	.ldevs = 		scx200_logical_devs,
+	.activate_one = 	scx200_activate_one_logical,
+	.deactivate_one =	scx200_deactivate_one_logical,
+};
+
+static struct sc_chip_id scx200_sio_ids[] = {
+	{"SCx200/SC1100", 0xF5},
+};
+
+static unsigned long private_base;
+
+static struct pci_device_id scx200_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE)},
+	{PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE)},
+	{},
+};
+
+MODULE_DEVICE_TABLE(pci, scx200_tbl);
+
+static int scx200_pci_probe(struct pci_dev *, const struct pci_device_id *);
+
+static struct pci_driver scx200_pci_driver = {
+	.name = "scx200",
+	.id_table = scx200_tbl,
+	.probe = scx200_pci_probe,
+};
+
+void scx200_write_reg(struct sc_dev *dev, u8 reg, u8 val)
+{
+	outb(reg, dev->base_index);
+	outb(val, dev->base_data);
+}
+
+u8 scx200_read_reg(struct sc_dev *dev, u8 reg)
+{
+	u8 val;
+
+	outb(reg, dev->base_index);
+	val = inb(dev->base_data);
+
+	return val;
+}
+
+static u8 scx200_gpio_read(void *data, int pin_number)
+{
+	u32 val;
+	int bank;
+	unsigned long base;
+	struct logical_dev *ldev = (struct logical_dev *)data;
+
+	if (pin_number > 63 || pin_number < 0)
+		return 0;
+
+	bank = 0;
+	base = ldev->base_addr;
+
+	if (pin_number > 31) {
+		bank = 1;
+		base = ldev->base_addr + 0x10;
+		pin_number -= 32;
+	}
+
+	val = inl(base + 0x04);
+
+	return ((val >> pin_number) & 0x01);
+}
+
+static void scx200_gpio_write(void *data, int pin_number, u8 byte)
+{
+	u32 val;
+	int bank;
+	unsigned long base;
+	struct logical_dev *ldev = (struct logical_dev *)data;
+
+	if (pin_number > 63 || pin_number < 0)
+		return;
+
+	bank = 0;
+	base = ldev->base_addr;
+
+	if (pin_number > 31) {
+		bank = 1;
+		base = ldev->base_addr + 0x10;
+		pin_number -= 32;
+	}
+
+	val = inl(base);
+
+	if (byte)
+		val |= (1 << pin_number);
+	else
+		val &= ~(1 << pin_number);
+
+	outl(val, base);
+}
+
+void scx200_gpio_control(void *data, int pin_number, u8 mask, u8 ctl)
+{
+	u32 val;
+	int bank;
+	unsigned long base;
+	struct logical_dev *ldev = (struct logical_dev *)data;
+
+	if (pin_number > 63 || pin_number < 0)
+		return;
+
+	bank = 0;
+	base = ldev->base_addr;
+
+	if (pin_number > 31) {
+		bank = 1;
+		base = ldev->base_addr + 0x10;
+		pin_number -= 32;
+	}
+
+	/*
+	 * Pin selection.
+	 */
+
+	val = 0;
+	val = ((bank & 0x01) << 5) | pin_number;
+	outl(val, ldev->base_addr + 0x20);
+
+	val = inl(ldev->base_addr + 0x24);
+
+	val &= 0x7f;
+	val &= mask;
+	val |= ctl;
+
+	outl(val, ldev->base_addr + 0x24);
+}
+
+int scx200_gpio_activate(void *data)
+{
+	return 0;
+}
+
+static int scx200_ldev_index_by_name(char *name)
+{
+	int i;
+
+	for (i = 0;
+	     i < sizeof(scx200_logical_devs) / sizeof(scx200_logical_devs[0]); ++i)
+		if (!strncmp(scx200_logical_devs[i].name, name, SC_NAME_LEN))
+			return i;
+
+	return -ENODEV;
+}
+
+static int scx200_chip_index(u8 id)
+{
+	int i;
+
+	for (i = 0; i < sizeof(scx200_sio_ids) / sizeof(scx200_sio_ids[0]); ++i)
+		if (scx200_sio_ids[i].id == id)
+			return i;
+
+	return -ENODEV;
+}
+
+static int scx200_probe(void *data, unsigned long base)
+{
+	unsigned long size = 2;
+	u8 id;
+	int chip_num;
+	struct sc_dev *dev = (struct sc_dev *)data;
+
+	/*
+	 * Special address to handle.
+	 */
+	if (base == 0) {
+		return scx200_probe(data, 0x015C);
+	}
+
+	dev->base_index = base;
+	dev->base_data = base + 1;
+
+	id = scx200_read_reg(dev, SIO_REG_SID);
+	chip_num = scx200_chip_index(id);
+
+	if (chip_num >= 0) {
+		printk(KERN_INFO "Found %s [0x%x] at 0x%04lx-0x%04lx.\n",
+		       scx200_sio_ids[chip_num].name,
+		       scx200_sio_ids[chip_num].id, base, base + size - 1);
+		return 0;
+	}
+
+	printk(KERN_INFO "Found nothing at 0x%04lx-0x%04lx.\n", 
+			base, base + size - 1);
+
+	return -ENODEV;
+}
+
+static int scx200_pci_probe(struct pci_dev *pdev,
+			    const struct pci_device_id *ent)
+{
+	private_base = pci_resource_start(pdev, 0);
+	printk(KERN_INFO "%s: GPIO base 0x%lx.\n", pci_name(pdev), private_base);
+
+	if (!request_region
+	    (private_base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO")) {
+		printk(KERN_ERR "%s: failed to request %d bytes I/O region for GPIOs.\n",
+		       pci_name(pdev), SCx200_GPIO_SIZE);
+		return -EBUSY;
+	}
+
+	pci_set_drvdata(pdev, &private_base);
+	pci_enable_device(pdev);
+
+	return 0;
+}
+
+static int scx200_deactivate_one_logical(struct logical_dev *ldev)
+{
+	if (ldev->index != LDEV_PRIVATE)
+		return -ENODEV;
+
+	private_base -= 0x10;
+
+	return 0;
+}
+
+static int scx200_find_private_device(struct logical_dev *ldev)
+{
+	struct sc_dev *dev = (struct sc_dev *)ldev->pdev;
+
+	/*
+	 * SCx200/SC1100 has only GPIO in it's private space.
+	 */
+
+	if (strncmp(ldev->name, "GPIO", SC_NAME_LEN)) {
+		printk(KERN_ERR "Logical device %s at private space is not supported in chip %s.\n",
+		       ldev->name, dev->name);
+		return -ENODEV;
+	}
+
+	ldev->base_addr = private_base;
+	private_base += 0x10;
+
+	ldev->read = scx200_gpio_read;
+	ldev->write = scx200_gpio_write;
+	ldev->control = scx200_gpio_control;
+	ldev->activate = scx200_gpio_activate;
+
+	return 0;
+}
+
+static int scx200_activate_one_logical(struct logical_dev *ldev)
+{
+	int err, idx;
+	struct sc_dev *dev = ldev->pdev;
+	u8 active;
+
+	idx = scx200_ldev_index_by_name(ldev->name);
+	if (idx < 0) {
+		printk(KERN_INFO "Chip %s does not have logical device %s at %x.\n",
+		       dev->name, ldev->name, ldev->index);
+		return -ENODEV;
+	}
+
+	if (scx200_logical_devs[idx].id == LDEV_PRIVATE) {
+		err = scx200_find_private_device(ldev);
+		if (err)
+			return err;
+
+		printk(KERN_INFO "\t%16s - found at 0x%lx.\n", 
+				ldev->name, ldev->base_addr);
+	} else {
+		scx200_write_reg(dev, SIO_REG_LDN, ldev->index);
+		active = scx200_read_reg(dev, SIO_REG_ACTIVE);
+		if ((active & SIO_ACTIVE_EN) == 0) {
+			printk(KERN_INFO "\t%16s - not activated at %x: activating... ",
+			       ldev->name, ldev->index);
+
+			scx200_write_reg(dev, SIO_REG_ACTIVE,
+					 active | SIO_ACTIVE_EN);
+			active = scx200_read_reg(dev, SIO_REG_ACTIVE);
+			if ((active & SIO_ACTIVE_EN) == 0) {
+				printk("failed.\n");
+				return -ENODEV;
+			}
+			printk("done.\n");
+		}
+
+		ldev->base_addr = scx200_read_reg(dev, SIO_REG_IO_LSB);
+		ldev->base_addr |= (scx200_read_reg(dev, SIO_REG_IO_MSB) << 8);
+	}
+
+	err = ldev->activate(ldev);
+	if (err < 0) {
+		printk(KERN_INFO "\t%16s - not activated: ->activate() failed with error code %d.\n",
+				ldev->name, err);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "\t%16s - activated at %x: 0x%04lx-0x%04lx\n",
+	       ldev->name, ldev->index, ldev->base_addr,
+	       ldev->base_addr + ldev->range);
+
+	return 0;
+}
+
+static int scx200_init(void)
+{
+	int err;
+
+	err = pci_module_init(&scx200_pci_driver);
+	if (err) {
+		printk(KERN_ERR "Failed to register PCI driver for device %s : err=%d.\n",
+		       scx200_pci_driver.name, err);
+		return err;
+	}
+
+	err = sc_add_sc_dev(&scx200_dev);
+	if (err)
+		return err;
+
+	printk(KERN_INFO "Driver for %s SuperIO chip.\n", scx200_dev.name);
+	return 0;
+}
+
+static void scx200_fini(void)
+{
+	sc_del_sc_dev(&scx200_dev);
+
+	while (atomic_read(&scx200_dev.refcnt))
+	{
+		printk(KERN_INFO "Waiting for %s to became free: refcnt=%d.\n",
+				scx200_dev.name, atomic_read(&scx200_dev.refcnt));
+		
+		msleep_interruptible(1000);
+
+		if (signal_pending(current))
+			flush_signals(current);
+		
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_FREEZE);
+	}
+
+	pci_unregister_driver(&scx200_pci_driver);
+	if (private_base)
+		release_region(private_base, SCx200_GPIO_SIZE);
+}
+
+module_init(scx200_init);
+module_exit(scx200_fini);
+
+EXPORT_SYMBOL(scx200_write_reg);
+EXPORT_SYMBOL(scx200_read_reg);
diff -Nru a/drivers/superio/scx.h b/drivers/superio/scx.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/superio/scx.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,28 @@
+/*
+ * 	scx.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __SCX200_H
+#define __SCX200_H
+
+#define SCx200_GPIO_SIZE 	0x2c
+
+#endif /* __SCX200_H */
diff -Nru a/drivers/w1/w1.c b/drivers/w1/w1.c
--- a/drivers/w1/w1.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/w1/w1.c	2005-03-30 17:24:44 -08:00
@@ -522,10 +522,11 @@
 		slave_count++;
 	}
 
-		if (slave_count == dev->slave_count && rn ) {
-			tmp = cpu_to_le64(rn);
-			if(((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&tmp, 7))
-				w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
+	rn = cpu_to_le64(rn);
+
+	if (slave_count == dev->slave_count &&
+		rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
+		w1_attach_slave_device(dev, tmp);
 	}
 			
 	atomic_dec(&dev->refcnt);
diff -Nru a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c
--- a/drivers/w1/w1_smem.c	2005-03-30 17:24:44 -08:00
+++ b/drivers/w1/w1_smem.c	2005-03-30 17:24:44 -08:00
@@ -60,7 +60,7 @@
 	int i;
 	ssize_t count = 0;
 	
-	for (i = 0; i < 9; ++i)
+	for (i = 0; i < 8; ++i)
 		count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
 	count += sprintf(buf + count, "\n");
 
@@ -87,7 +87,7 @@
 		count = 0;
 		goto out;
 	}
-	for (i = 0; i < 9; ++i)
+	for (i = 0; i < 8; ++i)
 		count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
 	count += sprintf(buf + count, "\n");
 	
diff -Nru a/include/linux/connector.h b/include/linux/connector.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/connector.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,150 @@
+/*
+ * 	connector.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CONNECTOR_H
+#define __CONNECTOR_H
+
+#include <asm/types.h>
+
+#define CN_IDX_KOBJECT_UEVENT		0xabcd  /* Kobject's userspace events*/
+#define CN_VAL_KOBJECT_UEVENT		0x0000
+#define CN_IDX_SUPERIO			0xaabb  /* SuperIO subsystem */
+#define CN_VAL_SUPERIO			0xccdd
+
+
+#define CONNECTOR_MAX_MSG_SIZE 	1024
+
+struct cb_id
+{
+	__u32			idx;
+	__u32			val;
+};
+
+struct cn_msg
+{
+	struct cb_id 		id;
+
+	__u32			seq;
+	__u32			ack;
+
+	__u32			len;		/* Length of the following data */
+	__u8			data[0];
+};
+
+struct cn_notify_req
+{
+	__u32			first;
+	__u32			range;
+};
+
+struct cn_ctl_msg
+{
+	__u32			idx_notify_num;
+	__u32			val_notify_num;
+	__u32			group;
+	__u32			len;
+	__u8			data[0];
+};
+
+
+#ifdef __KERNEL__
+
+#include <asm/atomic.h>
+
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+#include <net/sock.h>
+
+#define CN_CBQ_NAMELEN		32
+
+struct cn_queue_dev
+{
+	atomic_t		refcnt;
+	unsigned char		name[CN_CBQ_NAMELEN];
+
+	struct workqueue_struct	*cn_queue;
+	
+	struct list_head 	queue_list;
+	spinlock_t 		queue_lock;
+
+	int			netlink_groups;
+	struct sock		*nls;
+};
+
+struct cn_callback
+{
+	unsigned char		name[CN_CBQ_NAMELEN];
+	
+	struct cb_id		id;
+	void			(* callback)(void *);
+	void			*priv;
+	
+	atomic_t		refcnt;
+};
+
+struct cn_callback_entry
+{
+	struct list_head	callback_entry;
+	struct cn_callback	*cb;
+	struct work_struct	work;
+	struct cn_queue_dev	*pdev;
+	
+	void			(* destruct_data)(void *);
+	void			*ddata;
+
+	int			seq, group;
+	struct sock		*nls;
+};
+
+struct cn_ctl_entry
+{
+	struct list_head	notify_entry;
+	struct cn_ctl_msg	*msg;
+};
+
+struct cn_dev
+{
+	struct cb_id 		id;
+
+	u32			seq, groups;
+	struct sock 		*nls;
+	void 			(*input)(struct sock *sk, int len);
+
+	struct cn_queue_dev	*cbdev;
+};
+
+extern int cn_already_initialized;
+
+int cn_add_callback(struct cb_id *, char *, void (* callback)(void *));
+void cn_del_callback(struct cb_id *);
+void cn_netlink_send(struct cn_msg *, u32);
+
+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb);
+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cn_callback *cb);
+
+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *);
+void cn_queue_free_dev(struct cn_queue_dev *dev);
+
+int cn_cb_equal(struct cb_id *, struct cb_id *);
+
+#endif /* __KERNEL__ */
+#endif /* __CONNECTOR_H */
diff -Nru a/include/linux/i2c.h b/include/linux/i2c.h
--- a/include/linux/i2c.h	2005-03-30 17:24:44 -08:00
+++ b/include/linux/i2c.h	2005-03-30 17:24:44 -08:00
@@ -306,9 +306,6 @@
 #define ANY_I2C_BUS		0xffff
 #define ANY_I2C_ISA_BUS		9191
 
-/* The length of the option lists */
-#define I2C_CLIENT_MAX_OPTS 48
-
 
 /* ----- functions exported by i2c.o */
 
@@ -526,6 +523,9 @@
 #define I2C_MAJOR	89		/* Device major number		*/
 
 /* These defines are used for probing i2c client addresses */
+/* The length of the option lists */
+#define I2C_CLIENT_MAX_OPTS 48
+
 /* Default fill of many variables */
 #define I2C_CLIENT_DEFAULTS {I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
                           I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
@@ -544,19 +544,12 @@
                           I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
                           I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END}
 
-/* This is ugly. We need to evaluate I2C_CLIENT_MAX_OPTS before it is 
-   stringified */
-#define I2C_CLIENT_MODPARM_AUX1(x) "1-" #x "h"
-#define I2C_CLIENT_MODPARM_AUX(x) I2C_CLIENT_MODPARM_AUX1(x)
-#define I2C_CLIENT_MODPARM I2C_CLIENT_MODPARM_AUX(I2C_CLIENT_MAX_OPTS)
-
 /* I2C_CLIENT_MODULE_PARM creates a module parameter, and puts it in the
    module header */
 
 #define I2C_CLIENT_MODULE_PARM(var,desc) \
   static unsigned short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS; \
   static unsigned int var##_num; \
-  /*MODULE_PARM(var,I2C_CLIENT_MODPARM);*/ \
   module_param_array(var, short, &var##_num, 0); \
   MODULE_PARM_DESC(var,desc)
 
diff -Nru a/include/linux/sc_conn.h b/include/linux/sc_conn.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/sc_conn.h	2005-03-30 17:24:44 -08:00
@@ -0,0 +1,50 @@
+/*
+ * 	sc_conn.h
+ * 
+ * 2004 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SC_CONN_H
+#define __SC_CONN_H
+
+enum sc_conn_cmd
+{
+	SC_CMD_LDEV_READ = 0,
+	SC_CMD_LDEV_WRITE,
+	SC_CMD_LDEV_CONTROL,
+	SC_CMD_LDEV_ACTIVATE,
+
+	__SC_CMD_MAX_CMD_NUMBER
+};
+
+struct sc_conn_data
+{
+	char		sname[16];
+	char		lname[16];
+	__u32		idx;
+	
+	__u8		cmd;
+	__u8		p0, p1, p2;
+
+	__u8		data[0];
+};
+
+int sc_register_callback(void);
+void sc_unregister_callback(void);
+
+#endif /* __SC_CONN_H */
diff -Nru a/lib/kobject_uevent.c b/lib/kobject_uevent.c
--- a/lib/kobject_uevent.c	2005-03-30 17:24:44 -08:00
+++ b/lib/kobject_uevent.c	2005-03-30 17:24:44 -08:00
@@ -12,6 +12,7 @@
  *	Kay Sievers		<kay.sievers@vrfy.org>
  *	Arjan van de Ven	<arjanv@redhat.com>
  *	Greg Kroah-Hartman	<greg@kroah.com>
+ *	Evgeniy Polyakov 	<johnpol@2ka.mipt.ru>
  */
 
 #include <linux/spinlock.h>
@@ -21,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/kobject_uevent.h>
 #include <linux/kobject.h>
+#include <linux/connector.h>
 #include <net/sock.h>
 
 #define BUFFER_SIZE	1024	/* buffer for the hotplug env */
@@ -53,6 +55,70 @@
 #ifdef CONFIG_KOBJECT_UEVENT
 static struct sock *uevent_sock;
 
+#ifdef CONFIG_CONNECTOR
+static struct cb_id uid = {CN_IDX_KOBJECT_UEVENT, CN_VAL_KOBJECT_UEVENT};
+static void kobject_uevent_connector_callback(void *data)
+{
+}
+
+static void kobject_uevent_send_connector(const char *signal, const char *obj, char **envp, int gfp_mask)
+{
+	if (cn_already_initialized) {
+		int size;
+		struct cn_msg *msg;
+		static int uevent_connector_initialized;
+		
+		if (!uevent_connector_initialized) {
+			cn_add_callback(&uid, "kobject_uevent", kobject_uevent_connector_callback);
+			uevent_connector_initialized = 1;
+		}
+
+
+		size = strlen(signal) + strlen(obj) + 2 + BUFFER_SIZE + sizeof(*msg);
+		msg = kmalloc(size, gfp_mask);
+		if (msg) {
+			u8 *pos;
+			int len;
+
+			memset(msg, 0, size);
+
+			msg->len = size - sizeof(*msg);
+
+			memcpy(&msg->id, &uid, sizeof(msg->id));
+			
+			size -= sizeof(*msg);
+
+			pos = (u8 *)(msg + 1);
+			
+			len = snprintf(pos, size, "%s@%s", signal, obj);
+			len++;
+			size -= len;
+			pos += len;
+			
+			if (envp) {
+				int i;
+
+				for (i = 2; envp[i]; i++) {
+					len = strlen(envp[i]) + 1;
+					snprintf(pos, size, "%s", envp[i]);
+					size -= len;
+					pos += len;
+				}
+			}
+
+			cn_netlink_send(msg, 0);
+
+			kfree(msg);
+		}
+	}
+}
+#else
+static void kobject_uevent_send_connector(const char *signal, const char *obj, char **envp, int gfp_mask)
+{
+}
+#endif
+
+
 /**
  * send_uevent - notify userspace by sending event trough netlink socket
  *
@@ -92,6 +158,8 @@
 			strcpy(pos, envp[i]);
 		}
 	}
+
+	kobject_uevent_send_connector(signal, obj, envp, gfp_mask);
 
 	return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask);
 }