bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 khali@linux-fr.org[gregkh]|ChangeSet|20050225215423|27450 khali # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/02/25 13:54:23-08:00 khali@linux-fr.org # [PATCH] Add class definition to the elektor bus driver # # Hi Frank, all, # # > > Which bus driver are you using? It obviously lacks class declaration, # > > so the correct fix is to add the class there. # > # > The modules that are loading are (in reverse order): # > adm1031 # > ad5321 # > mic184 # > pca9540 # > i2c_sensor # > i2c_elektor # > i2c_algo_pcf # > i2c_core # > # > So I believe what you are asking for is the i2c_elektor driver for the # > PCF8584 ISA to I2C chip. # # Correct, I just checked and this one actually lacks its class. Patch # follows. # # This patch adds a class definition to the elektor i2c bus driver. # Without this definition, hardware monitoring chips located on such # busses cannot possibly be driven. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/busses/i2c-elektor.c # 2005/02/25 11:41:26-08:00 khali@linux-fr.org +1 -0 # Add class definition to the elektor bus driver # # ChangeSet # 2005/02/25 13:40:29-08:00 minyard@acm.org # [PATCH] I2C: minor I2C cleanups # # This is one in a series of patches for adding a non-blocking interface # to the I2C driver for supporting the IPMI SMBus driver. This patch is a # simply some minor cleanups and is in addition to the patch by Mickey # Stein (http://marc.theaimsgroup.com/?l=linux-kernel&m=110919738708916&w=2). # # Clean up some general I2C things. Fix some grammar and put () # around all the #defines that are compound to avoid nasty # side-effects. # # Signed-off-by: Corey Minyard # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c.h # 2005/02/24 16:00:00-08:00 minyard@acm.org +25 -25 # I2C: minor I2C cleanups # # ChangeSet # 2005/02/25 12:08:52-08:00 ben-linux@fluff.org # [PATCH] I2C: S3C2410 missing I2C_CLASS_HWMON # # None of the standard sensor drivers currently recognise the s3c24xx # I2C controller as it does not have I2C_CLASS_HWMON set in the # adapter class field. # # The attached patch initialises the adapter class to I2C_CLASS_HWMON # # Signed-off-by: Ben Dooks # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/busses/i2c-s3c2410.c # 2005/02/21 02:52:12-08:00 ben-linux@fluff.org +1 -0 # I2C: S3C2410 missing I2C_CLASS_HWMON # # ChangeSet # 2005/02/25 12:08:35-08:00 yekkim@pacbell.net # [PATCH] I2C: Fix some gcc 4.0 compile failures and warnings # # gcc 4.0.x cvs seems to dislike "include/linux/i2c.h file" and others due # to a current gcc 4.0.x change having to do with array declarations. # # Example error msg: include/linux/i2c.h:{55,194} error: array type has # incomplete element type # # A. Daplas has recently done a workaround for this on another header # file. A thread discussing this can be found by following the link below: # # http://gcc.gnu.org/ml/gcc/2005-02/msg00053.html # # The patch changes the array(struct i2c_msg) declaration used by # *i2c_transfer and *master_xfer from "struct i2c_msg msg[]" format to # "struct i2c_msg *msg". # # After some grepping, I came up with about a dozen files that used the # format disliked by gcc4 that're addressed by the attached patch. # Tested on gcc 3.x & gcc 4.x by configuring kernel with all i2c switches # enabled as module, and saw no errors or warnings in i2c. # # Signed-off-by: Mickey Stein # Signed-off-by: Greg Kroah-Hartman # # include/media/saa7146.h # 2005/02/23 12:19:38-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # include/linux/i2c.h # 2005/02/23 10:46:23-08:00 yekkim@pacbell.net +2 -2 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/media/video/saa7134/saa7134-i2c.c # 2005/02/23 12:30:20-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/media/video/bttv-i2c.c # 2005/02/23 12:30:56-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c # 2005/02/23 10:50:07-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c # 2005/02/23 12:31:38-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/media/dvb/b2c2/skystar2.c # 2005/02/23 10:50:42-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/media/common/saa7146_i2c.c # 2005/02/23 12:32:45-08:00 yekkim@pacbell.net +4 -4 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/i2c-core.c # 2005/02/23 10:49:18-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/busses/i2c-s3c2410.c # 2005/02/23 12:20:31-08:00 yekkim@pacbell.net +2 -2 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/busses/i2c-mpc.c # 2005/02/23 12:17:28-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/busses/i2c-keywest.c # 2005/02/23 12:26:47-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/busses/i2c-iop3xx.c # 2005/02/23 10:47:36-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/busses/i2c-ibm_iic.c # 2005/02/23 12:21:08-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/busses/i2c-au1550.c # 2005/02/23 12:27:39-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/algos/i2c-algo-sgi.c # 2005/02/23 12:29:58-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/algos/i2c-algo-pcf.c # 2005/02/23 12:28:49-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/algos/i2c-algo-pca.c # 2005/02/23 12:28:09-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # drivers/i2c/algos/i2c-algo-ite.c # 2005/02/23 12:29:31-08:00 yekkim@pacbell.net +2 -2 # I2C: Fix some gcc 4.0 compile failures and warnings # # Documentation/i2c/writing-clients # 2005/02/23 10:42:30-08:00 yekkim@pacbell.net +1 -1 # I2C: Fix some gcc 4.0 compile failures and warnings # # ChangeSet # 2005/02/25 12:08:16-08:00 khali@linux-fr.org # [PATCH] I2C: Make i2c list terminators explicitely unsigned # # Shouldn't the i2c list terminators be explicitely declared as unsigned? # I'd hope it to help code analysis tools and possibly avoid false # positives. Coverity's SWAT pointed my attention to these constants. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c.h # 2005/02/24 03:36:30-08:00 khali@linux-fr.org +2 -2 # I2C: Make i2c list terminators explicitely unsigned # # ChangeSet # 2005/02/25 12:07:57-08:00 khali@linux-fr.org # [PATCH] I2C: Remove NULL client checks in rtc8564 driver # # Several functions in your rtc8564 driver verify the non-NULLity of the # i2c client that is passed to them. It doesn't seem to be necessary, as I # can't think of any case where these functions could possibly be called # with a NULL i2c client. As a matter of fact, I couldn't find any similar # driver doing such checks. # # My attention was brought on this by Coverity's SWAT which correctly # noticed that three of these functions contain explicit or hidden # dereferences of the i2c client pointer *before* the NULL check. I guess # it wasn't a problem because the NULL case cannot happen (unless I miss # something), but this still is confusing code. # # Thus I propose the following changes: # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/rtc8564.c # 2005/02/24 02:56:52-08:00 khali@linux-fr.org +8 -8 # I2C: Remove NULL client checks in rtc8564 driver # # ChangeSet # 2005/02/17 15:53:56-08:00 hfvogt@gmx.net # [PATCH] I2C i2c-nforce2: add support for nForce4 (patch against 2.6.11-rc4) # # can you please apply the attached patch (against 2.6.11-rc4, but works # as well for 2.6.11-rc3-mm2), that adds support for the two SMBusses of # the nForce4 to the i2c-nforce2 i2c bus driver. The patch is reported to # work on the standard nForce4 (i.e. non-Ultra, non-SLI), but I expect # that it works as well for the other nForce4 chipsets, that seem to have # the same PCI-id for the SMBus-device. # # This patch was proposed by Chuck , thanks to him for the # information, testing and his patch. # # Signed-off-by: Hans-Frieder Vogt # Signed-off-by: Greg Kroah-Hartman # # include/linux/pci_ids.h # 2005/02/17 14:54:57-08:00 hfvogt@gmx.net +1 -0 # I2C i2c-nforce2: add support for nForce4 (patch against 2.6.11-rc4) # # drivers/i2c/busses/i2c-nforce2.c # 2005/02/17 14:53:53-08:00 hfvogt@gmx.net +4 -2 # I2C i2c-nforce2: add support for nForce4 (patch against 2.6.11-rc4) # # ChangeSet # 2005/02/17 14:53:16-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into bix.(none):/usr/src/bk-i2c # # include/linux/i2c-id.h # 2005/02/17 14:53:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/w83781d.c # 2005/02/17 14:53:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/via686a.c # 2005/02/17 14:53:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/pc87360.c # 2005/02/17 14:53:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/it87.c # 2005/02/17 14:53:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/ds1621.c # 2005/02/17 14:53:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/02/17 14:35:26-08:00 gregkh@suse.de # [PATCH] I2C: fixed up the i2c-id.h algo ids. # # Thanks to Jean Delvare for the help with this. # # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c-id.h # 2005/02/17 14:34:08-08:00 gregkh@suse.de +9 -6 # I2C: fixed up the i2c-id.h algo ids. # # ChangeSet # 2005/02/17 14:23:52-08:00 icampbell@arcom.com # [PATCH] I2C: fix typo in drivers/i2c/busses/i2c-ixp4xx.c # # I was looking at your ixp4xx gpio i2c driver for inspiration (for a # similar pxa2xx one) and I just happened to notice a tiny typo. # # Signed-off-by: Ian Campbell # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/busses/i2c-ixp4xx.c # 2005/02/17 04:13:02-08:00 icampbell@arcom.com +2 -2 # I2C: fix typo in drivers/i2c/busses/i2c-ixp4xx.c # # ChangeSet # 2005/02/17 14:23:31-08:00 macro@linux-mips.org # [PATCH] I2C: Enable I2C_PIIX4 for 64-bit platforms # # Is there any specific reason for the PIIX4 SMBus driver to be disabled on # 64-bit platforms? If not, then please apply the following change. The # MIPS Technologies Malta development board has the 82371EB chip and # supports 64-bit configurations. I've verified the driver to work # correctly using 64-bit kernels for both endiannesses. # # Signed-off-by: Maciej W. Rozycki # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/busses/Kconfig # 2005/01/26 11:48:36-08:00 macro@linux-mips.org +1 -1 # I2C: Enable I2C_PIIX4 for 64-bit platforms # # ChangeSet # 2005/02/17 14:23:10-08:00 icampbell@arcom.com # [PATCH] I2C: improve debugging output # # Rework the pca_xfer() function to always print the number of # successfully completed transfers in a series when debugging, even when # exiting with an error. # # Signed-off-by: Ian Campbell # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/algos/i2c-algo-pca.c # 2005/02/11 07:21:10-08:00 icampbell@arcom.com +16 -12 # I2C: improve debugging output # # ChangeSet # 2005/02/17 14:22:49-08:00 maartendeprez@scarlet.be # [PATCH] I2C: add GL520SM Sensor Chip driver # # Port of the Genesys Logic 520SM sensor chip driver from linux 2.4 # # Signed-off-by: Maarten Deprez # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/gl520sm.c # 2005/02/11 07:14:31-08:00 maartendeprez@scarlet.be +754 -0 # I2C: add GL520SM Sensor Chip driver # # drivers/i2c/chips/Makefile # 2005/02/11 07:14:31-08:00 maartendeprez@scarlet.be +1 -0 # I2C: add GL520SM Sensor Chip driver # # drivers/i2c/chips/Kconfig # 2005/02/11 07:14:31-08:00 maartendeprez@scarlet.be +11 -0 # I2C: add GL520SM Sensor Chip driver # # drivers/i2c/chips/gl520sm.c # 2005/02/11 07:14:31-08:00 maartendeprez@scarlet.be +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/gl520sm.c # # ChangeSet # 2005/02/17 14:22:27-08:00 mgreer@mvista.com # [PATCH] I2C: add Marvell mv64xxx i2c driver # # Marvell makes a line of host bridge for PPC and MIPS systems. On those # bridges is an i2c controller. This patch adds the driver for that i2c # controller. # # Please apply. # # Depends on patch submitted by Jean Delvare: # http://archives.andrew.net.au/lm-sensors/msg29405.html # # Signed-off-by: Mark A. Greer # Signed-off-by: Greg Kroah-Hartman # # include/linux/mv643xx.h # 2005/02/09 13:32:24-08:00 mgreer@mvista.com +11 -6 # I2C: add Marvell mv64xxx i2c driver # # include/linux/i2c-id.h # 2005/02/09 13:32:24-08:00 mgreer@mvista.com +3 -0 # I2C: add Marvell mv64xxx i2c driver # # drivers/i2c/busses/i2c-mv64xxx.c # 2005/02/09 13:32:24-08:00 mgreer@mvista.com +596 -0 # I2C: add Marvell mv64xxx i2c driver # # drivers/i2c/busses/Makefile # 2005/02/09 13:32:24-08:00 mgreer@mvista.com +1 -0 # I2C: add Marvell mv64xxx i2c driver # # drivers/i2c/busses/Kconfig # 2005/02/09 13:32:24-08:00 mgreer@mvista.com +10 -0 # I2C: add Marvell mv64xxx i2c driver # # drivers/i2c/busses/i2c-mv64xxx.c # 2005/02/09 13:32:24-08:00 mgreer@mvista.com +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/busses/i2c-mv64xxx.c # # ChangeSet # 2005/02/17 14:22:05-08:00 aurelien@aurel32.net # [PATCH] I2C: New chip driver: sis5595 # # Please find below the new version of the patch against kernel # 2.6.11-rc3-mm1 to add the sis5595 driver (sensor part). # # As you suggested, I have changed the PCI part of the driver, taking the # via686a driver as an example. I have also changed the comparison of # jiffies by using time_after. # # # Signed-off-by: Aurelien Jarno # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/sis5595.c # 2005/02/06 12:14:44-08:00 aurelien@aurel32.net +794 -0 # I2C: New chip driver: sis5595 # # drivers/i2c/chips/Makefile # 2005/02/06 11:30:07-08:00 aurelien@aurel32.net +1 -0 # I2C: New chip driver: sis5595 # # drivers/i2c/chips/Kconfig # 2005/02/06 11:30:07-08:00 aurelien@aurel32.net +12 -0 # I2C: New chip driver: sis5595 # # drivers/i2c/chips/sis5595.c # 2005/02/06 12:14:44-08:00 aurelien@aurel32.net +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/sis5595.c # # ChangeSet # 2005/02/17 14:21:43-08:00 mgreer@mvista.com # [PATCH] I2C: add ST M41T00 I2C RTC chip driver # # This patch adds support for the ST M41T00 I2C RTC chip. # # This rtc chip has no mechanism to freeze it's registers while being # read; however, it will delay updating the external values of the # registers for 250ms after a register is read. To ensure that a sane # time value is read, the driver verifies that the same registers values # were read twice before returning. # # Also, when setting the rtc from an interrupt handler, a tasklet is used # to provide the context required by the i2c core code. # # # Signed-off-by: Mark A. Greer # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/m41t00.c # 2005/02/04 16:00:45-08:00 mgreer@mvista.com +247 -0 # I2C: add ST M41T00 I2C RTC chip driver # # drivers/i2c/chips/m41t00.c # 2005/02/04 16:00:45-08:00 mgreer@mvista.com +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/m41t00.c # # drivers/i2c/chips/Makefile # 2005/02/04 16:00:45-08:00 mgreer@mvista.com +1 -0 # I2C: add ST M41T00 I2C RTC chip driver # # drivers/i2c/chips/Kconfig # 2005/02/04 16:00:45-08:00 mgreer@mvista.com +9 -0 # I2C: add ST M41T00 I2C RTC chip driver # # ChangeSet # 2005/02/17 14:21:21-08:00 adobriyan@mail.ru # [PATCH] I2C: use time_after instead of comparing jiffies # # Signed-off-by: Alexey Dobriyan # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/w83l785ts.c # 2005/02/01 23:38:40-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/w83781d.c # 2005/02/01 23:36:51-08:00 adobriyan@mail.ru +3 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/w83627hf.c # 2005/02/01 23:34:43-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/via686a.c # 2005/02/02 00:25:11-08:00 adobriyan@mail.ru +3 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/smsc47m1.c # 2005/02/01 23:31:57-08:00 adobriyan@mail.ru +2 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/smsc47b397.c # 2005/02/02 00:23:21-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/pc87360.c # 2005/02/02 00:22:48-08:00 adobriyan@mail.ru +2 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/max1619.c # 2005/02/02 00:49:43-08:00 adobriyan@mail.ru +2 -4 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm90.c # 2005/02/02 00:20:44-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm87.c # 2005/02/02 00:49:53-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm85.c # 2005/02/01 23:15:28-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm83.c # 2005/02/02 00:19:16-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm80.c # 2005/02/02 00:18:13-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm78.c # 2005/02/01 23:11:53-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm77.c # 2005/02/01 23:10:51-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm75.c # 2005/02/01 23:09:33-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/lm63.c # 2005/02/02 00:17:04-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/it87.c # 2005/02/01 23:06:30-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/gl518sm.c # 2005/02/01 23:03:35-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/fscher.c # 2005/02/02 00:16:12-08:00 adobriyan@mail.ru +2 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/eeprom.c # 2005/02/01 22:59:34-08:00 adobriyan@mail.ru +2 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/ds1621.c # 2005/02/01 22:58:03-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/asb100.c # 2005/02/01 22:56:44-08:00 adobriyan@mail.ru +2 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/adm1031.c # 2005/02/02 00:14:39-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/adm1026.c # 2005/02/02 00:13:48-08:00 adobriyan@mail.ru +4 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/adm1025.c # 2005/02/02 00:49:23-08:00 adobriyan@mail.ru +2 -3 # I2C: use time_after instead of comparing jiffies # # drivers/i2c/chips/adm1021.c # 2005/02/01 22:49:48-08:00 adobriyan@mail.ru +3 -2 # I2C: use time_after instead of comparing jiffies # # ChangeSet # 2005/02/17 13:53:53-08:00 c.lucas@ifrance.com # [PATCH] drivers/w1/*: convert to pci_register_driver # # convert from pci_module_init to pci_register_driver # (from:http://kerneljanitors.org/TODO). # # Signed-off-by: Christophe Lucas # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/matrox_w1.c # 2005/02/07 00:39:30-08:00 c.lucas@ifrance.com +1 -1 # drivers/w1/*: convert to pci_register_driver # # ChangeSet # 2005/02/17 13:53:33-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/superio/sc.c # 2005/02/07 07:45:10-08:00 johnpol@2ka.mipt.ru +24 -2 # superio: get rid of the potential problems with atomic operations. # # ChangeSet # 2005/02/17 13:53:13-08:00 johnpol@2ka.mipt.ru # [PATCH] w1: 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 # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/w1_therm.c # 2005/02/07 06:48:52-08:00 johnpol@2ka.mipt.ru +2 -0 # w1: get rid of the potential problems with atomic operations. # # drivers/w1/w1_family.c # 2005/02/07 06:48:52-08:00 johnpol@2ka.mipt.ru +2 -0 # w1: get rid of the potential problems with atomic operations. # # ChangeSet # 2005/02/17 13:52:53-08:00 johnpol@2ka.mipt.ru # [PATCH] w1: replace obsoleted *sleep_on* # # Remove obsoleded *sleep_on*. # # Since they are used only to wait for a given flags and awakening # only happens on signals, we can just replace them with # msleep_interruptible. # # Signed-off-by: Evgeniy Polyakov # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/w1_int.c # 2005/02/03 04:59:37-08:00 johnpol@2ka.mipt.ru +0 -1 # w1: replace obsoleted *sleep_on* # # drivers/w1/w1.h # 2005/02/03 04:59:37-08:00 johnpol@2ka.mipt.ru +0 -1 # w1: replace obsoleted *sleep_on* # # drivers/w1/w1.c # 2005/02/03 06:06:39-08:00 johnpol@2ka.mipt.ru +5 -13 # w1: replace obsoleted *sleep_on* # # ChangeSet # 2005/02/17 13:23:55-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 # Signed-off-by: Greg Kroah-Hartman # # lib/kobject_uevent.c # 2005/02/06 01:55:15-08:00 johnpol@2ka.mipt.ru +2 -0 # kobject_uevent: prefill allocated buffer with 0 before use. # # ChangeSet # 2005/02/17 13:23:37-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/connector/connector.c # 2005/02/16 16:00:00-08:00 johnpol@2ka.mipt.ru +7 -2 # connector: fix skb leak on big messages. # # ChangeSet # 2005/02/17 13:23:18-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/connector/connector.c # 2005/02/16 16:00:00-08:00 johnpol@2ka.mipt.ru +9 -2 # connector: allow sent to self messages. # # ChangeSet # 2005/02/17 13:22:58-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/connector/cn_queue.c # 2005/02/07 07:29:11-08:00 johnpol@2ka.mipt.ru +14 -2 # connector: get rid of the potential problems with atomic operations. # # ChangeSet # 2005/02/05 00:46:08-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into bix.(none):/usr/src/bk-i2c # # include/linux/i2c-id.h # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/w83781d.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/via686a.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/pc87360.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/it87.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/chips/ds1621.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/busses/i2c-viapro.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/i2c/busses/i2c-sis5595.c # 2005/02/05 00:46:04-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/02/04 10:37:43-08:00 greg@kroah.com # merge # # include/linux/i2c-id.h # 2005/02/04 10:37:21-08:00 greg@kroah.com +1 -1 # merge # # drivers/i2c/chips/w83781d.c # 2005/02/04 10:30:15-08:00 greg@kroah.com +0 -3 # Auto merged # # drivers/i2c/chips/via686a.c # 2005/02/04 10:30:14-08:00 greg@kroah.com +0 -17 # Auto merged # # drivers/i2c/chips/pc87360.c # 2005/02/04 10:30:14-08:00 greg@kroah.com +0 -35 # Auto merged # # drivers/i2c/chips/it87.c # 2005/02/04 10:30:14-08:00 greg@kroah.com +0 -4 # Auto merged # # drivers/i2c/chips/ds1621.c # 2005/02/04 10:30:14-08:00 greg@kroah.com +0 -8 # Auto merged # # drivers/i2c/busses/i2c-viapro.c # 2005/02/04 10:30:14-08:00 greg@kroah.com +0 -23 # Auto merged # # drivers/i2c/busses/i2c-sis5595.c # 2005/02/04 10:30:14-08:00 greg@kroah.com +0 -10 # Auto merged # # ChangeSet # 2005/02/03 12:51:50-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # drivers/i2c/chips/w83781d.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -3 # Auto merged # # drivers/i2c/chips/via686a.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -17 # Auto merged # # drivers/i2c/chips/pc87360.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -35 # Auto merged # # drivers/i2c/chips/it87.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -4 # Auto merged # # drivers/i2c/chips/ds1621.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -8 # Auto merged # # drivers/i2c/busses/i2c-viapro.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -23 # Auto merged # # drivers/i2c/busses/i2c-sis5595.c # 2005/02/03 12:51:45-08:00 akpm@bix.(none) +0 -10 # Auto merged # # ChangeSet # 2005/02/02 21:46:01-08:00 akpm@bix.(none) # aa # # include/linux/i2c-id.h # 2005/02/02 21:45:53-08:00 akpm@bix.(none) +0 -1 # aa # # ChangeSet # 2005/02/01 15:05:10-08:00 greg@kroah.com # Merge kroah.com:/home/greg/linux/BK/bleed-2.6 # into kroah.com:/home/greg/linux/BK/i2c-2.6 # # include/linux/i2c-id.h # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/w1/w1_family.c # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/w1/w1.c # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/media/video/saa5249.c # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/media/video/saa5246a.c # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/media/video/cx88/cx88-i2c.c # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/media/video/bttv-i2c.c # 2005/02/01 15:05:04-08:00 greg@kroah.com +0 -0 # Auto merged # # drivers/i2c/i2c-dev.c # 2005/02/01 15:05:03-08:00 greg@kroah.com +0 -0 # Auto merged # # ChangeSet # 2005/02/01 00:22:40-08:00 khali@linux-fr.org # [PATCH] I2C: Prevent buffer overflow on SMBus block read in # # Hi Greg, Linus, all, # # I just hit a buffer overflow while playing around with i2cdump and # i2c-viapro through i2c-dev. This is caused by a missing length check on # a buffer operation when doing a SMBus block read in the i2c-viapro # driver. The problem was already known and had been fixed upon report by # Sergey Vlasov back in August 2003 in lm_sensors (2.4 kernel version of # the driver) but for some reason it was never ported to the 2.6 kernel # version. # # I am not a security expert but I would guess that such a buffer overflow # could possibly be used to run arbitrary code in kernel space from user # space through i2c-dev. The severity obviously depends on the permisions # set on the i2c device files in /dev. Maybe it wouldn't be a bad idea to # push this patch upstream rather sooner than later. # # While I was at it, I also changed a similar size check (for SMBus block # write this time) in the same driver to use the correct constant # I2C_SMBUS_BLOCK_MAX instead of its current numerical value. This doesn't # change a thing at the moment but prevents another potential buffer # overflow in case the value of I2C_SMBUS_BLOCK_MAX were to be changed in # the future (admittedly unlikely though). # # > Now if we have broken hardware, then we might have a problem here, but # > otherwise I don't see it as a security issue right now. # # It doesn't take broken hardware. # # (Warning: I am going technical at this point, people not interested in # the gory details of the I2C and SMBus protocols should better stop here # ;)) # # It just depends on what part of the SMBus and I2C specifications a given # client chip supports. SMBus block reads are no different from SMBus byte # reads, except that the master (here the VIA Pro) goes on reading after # the first byte sent by the slave (which could be about anything, from # hardware monitoring chip to EEPROM). In that respect, it also doesn't # much differ from the I2C block read, which also starts in the exact same # way. The difference between SMBus block read and I2C block read is that # the first byte returned by the slave on SMBus block read is supposed to # be the remaining number of data byte to be sent, while this is simply # the first data byte for I2C block reads. # # To make it clearer, here comes the detail of the byte read, SMBus block # read and I2C block read commands (-> means from master to slave, <- # means from slave to master). See the official specifications for I2C and # SMBus for nicer graphics and additional details. # # Byte read: # -> client address, write mode # -> register address # -> client address, read mode # <- data byte # # SMBus block read: # -> client address, write mode # -> register address # -> client address, read mode # <- length byte (1 <=3D N <=3D 32) # <- first byte # <- next byte # <- ... # <- last (Nth) byte # # I2C block read: # -> client address, write mode # -> register address # -> client address, read mode # <- first byte # <- next byte # <- ... # <- last byte # # In each case, the *master* decides when to stop the transfer, not the # slave. # # There are two consequences for us here: # # 1* The client chip cannot differenciate between byte read and SMBus block # read until after it sent a first byte - which basically means that a # given register address is specified to be read with either command, not # both, and not using the correct one returns bogus results. i2c-dev # allows arbitrary commands so it is possible to ask for a SMBus block # read on a register that expects a simple byte read. The client # innocently will answer with the register value - which the master will # interpret as a length, and the master will then request that many # additional data bytes. If the client features autoincrement in this # register address range, it will most likely provide the value of the # next registers, if not it will dumbly return the same register value # again and again. # # This illustrates the fact that it doesn't take a broken chip to cause a # buffer overflow. It only takes a SMBus block read command on a register # for which the client did not expect it (and almost no client actually # supports SMBus block reads at the moment). If it happens that the # register value was greater than 32, the buffer overflow will occur # (without Sergey's fix, that is). So, with write access to the i2c # device files, it is actually very easy to trigger the buffer overflow, # providing there is at least one chip on the VIA Pro SMBus. # # 2* A client chip can obviously only implement SMBus block read or I2C # block read for a given register address, since the sequence sent by the # master is exactly the same. Not a big deal since a client chip is # designed either as an I2C slave or as a SMBus slave. However the master # doesn't know this, and i2c-dev allows arbitrary commands, so it is # possible to use an SMBus block read on an I2C slave which expected # instead an I2C block read, causing weird results. # # EEPROMs are such I2C slaves and they support I2C block reads. Now, # imagine that a non-write-protected EEPROM hangs on my VIA Pro SMBus (a # memory module SPD EEPROM would probably do), and for some reason i2c-dev # gives me access to it. I can write arbitrary bytes to the EEPROM using # simple byte writes. I could write the following bytes, in order, at some # location: 0x80, 34 null bytes, 94 bytes of nasty code. Then, still # through i2c-dev, I request a SMBus block read from the same location. # The EEPROM will answer as if it were an I2C block read (it can't # differenciate and doesn't support SMBus block reads anyway), i.e. it # will return as many bytes as requested, in order. The VIA Pro master # will however interpret the first byte (0x80) as a length, and will read # 128 bytes from the EEPROM, 34 of which will fill the data buffer, and 94 # will overflow. Providing I know how the kernel works, these 94 bytes # could be used for doing presumably bad things. # # This illustrates the fact that the user may actually control the buffer # overflow, indirectly, depending on what hardware is present on the bus. # EEPROMs are the most obvious way to do it, but some hardware monitoring # chips have RAM arrays that could presumably be used in a similar way. # # As a conclusion, I definitely agree that this buffer overflow isn't easy # to exploit, as it takes a particular combination of hardware and # non-standard permissions on i2c device files, and also requires very # good knowledge of the I2C and SMBus protocols; it is not impossible # though. # # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/busses/i2c-viapro.c # 2005/01/25 12:45:01-08:00 khali@linux-fr.org +4 -2 # I2C: Prevent buffer overflow on SMBus block read in # # ChangeSet # 2005/02/01 00:17:58-08:00 bunk@stusta.de # [PATCH] i2c-core.c: make some code static # # This patch makes some needlessly global code static. # # Signed-off-by: Adrian Bunk # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c.h # 2005/02/01 00:13:33-08:00 bunk@stusta.de +0 -2 # i2c-core.c: make some code static # # drivers/i2c/i2c-core.c # 2005/02/01 00:14:48-08:00 bunk@stusta.de +39 -40 # i2c-core.c: make some code static # # ChangeSet # 2005/02/01 00:11:50-08:00 greg@kroah.com # w1: fix some compiler warnings generated by the last "static" patch. # # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/dscore.h # 2005/02/01 00:11:27-08:00 greg@kroah.com +0 -3 # w1: fix some compiler warnings generated by the last "static" patch. # # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/dscore.c # 2005/02/01 00:11:27-08:00 greg@kroah.com +0 -3 # w1: fix some compiler warnings generated by the last "static" patch. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/02/01 00:08:56-08:00 johnpol@2ka.mipt.ru # [PATCH] w1: Core cleanup 1/2 # # Trivial cleanups, mostly static/non static, removed unneded exports. # It fuzzes a bit, sorry, patch is quite old. # # Signed-off-by: Evgeniy Polyakov # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/w1_int.c # 2005/01/31 16:00:00-08:00 johnpol@2ka.mipt.ru +0 -3 # w1: Core cleanup 1/2 # # drivers/w1/w1_family.c # 2005/01/31 16:00:00-08:00 johnpol@2ka.mipt.ru +0 -2 # w1: Core cleanup 1/2 # # drivers/w1/w1.c # 2005/01/31 16:00:00-08:00 johnpol@2ka.mipt.ru +10 -13 # w1: Core cleanup 1/2 # # ChangeSet # 2005/02/01 00:08:39-08:00 johnpol@2ka.mipt.ru # [PATCH] w1: dscore cleanups. 2/2 # # Trivial cleanups, mostly static/non static, removed unneded exports. # # Signed-off-by: Evgeniy Polyakov # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/dscore.c # 2005/01/31 16:00:00-08:00 johnpol@2ka.mipt.ru +14 -10 # w1: dscore cleanups. 2/2 # # ChangeSet # 2005/02/01 00:08:22-08:00 shawn.starr@rogers.com # [PATCH] I2C: lm80 driver improvement # # Description: Cleanup some cluttered macros, add error checking for fan divisor value set. # # Signed-off-by: Sytse Wielinga # Signed-off-by: Aurelien Jarno # Signed-off-by: Shawn Starr # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/lm80.c # 2005/01/26 09:31:26-08:00 shawn.starr@rogers.com +12 -5 # I2C: lm80 driver improvement # # ChangeSet # 2005/02/01 00:08:04-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/connector/connector.c # 2005/01/31 16:00:00-08:00 johnpol@2ka.mipt.ru +1 -1 # connector: Use DEFINE_SPINLOCK. # # ChangeSet # 2005/01/31 23:19:36-08:00 greg@kroah.com # I2C: fix duplicate algo ids. # # Thanks to Russell King for pointing this out. # # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c-id.h # 2005/01/31 23:19:16-08:00 greg@kroah.com +2 -2 # I2C: fix duplicate algo ids. # # Thanks to Russell King for pointing this out. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/31 10:32:07-08:00 mhoffman@lightlink.com # [PATCH] I2C: unnecessary #includes in asb100.c # # * Jean Delvare [2005-01-25 10:14:49 +0100]: # > Any reson why asb100.c (in linux 2.6.11-rc2) includes linux/ioport.h and # > asm/io.h? As an i2c-only chip driver, I don't think it needs these. # > # > As a side note, I also wonder what the inclusions of linux/config.h, # > linux/types.h and asm/errno.h are there for. # # Because they look pretty? Here's a patch Greg, please apply... # # Signed-off-by: Mark M. Hoffman # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/asb100.c # 2005/01/30 20:50:53-08:00 mhoffman@lightlink.com +0 -5 # I2C: unnecessary #includes in asb100.c # # ChangeSet # 2005/01/31 10:31:29-08:00 khali@linux-fr.org # [PATCH] I2C: Kill unused includes in i2c-sensor-detect.c # # Looks to me like i2c-sensor-detect.c includes a handful of headers it # doesn't need at all. This patch removes them. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/i2c-sensor-detect.c # 2005/01/28 13:51:09-08:00 khali@linux-fr.org +0 -7 # I2C: Kill unused includes in i2c-sensor-detect.c # # ChangeSet # 2005/01/31 10:30:41-08:00 khali@linux-fr.org # [PATCH] I2C: Do not show disabled pc87360 fans # # The pc87360 driver create sysfs files even for disabled fans. Since data # won't ever be updated, it doesn't make much sense. The following patch # adds some tests to only create the interface files that are actually # needed. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/pc87360.c # 2005/01/27 13:58:23-08:00 khali@linux-fr.org +35 -14 # I2C: Do not show disabled pc87360 fans # # ChangeSet # 2005/01/31 10:30:05-08:00 khali@linux-fr.org # [PATCH] I2C: Enable w83781d and w83627hf temperature channels # # The chips supported by the w83781d and w83627hf drivers might come up # with their temperature channels disabled. Currently, the w83781d driver # does so for temp3 but omits temp2, while the w83627hf driver omits both. # The following patch fixes that, and prints warning messages when the # driver has to enable the channels (normally the BIOS should do it for # us). We also skip this initialization step for the AS99127F chips, for # which we have no documentation. # # This should hopefully solve the problem reported here: # http://archives.andrew.net.au/lm-sensors/msg29150.html # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/w83781d.c # 2005/01/27 10:57:04-08:00 khali@linux-fr.org +20 -3 # I2C: Enable w83781d and w83627hf temperature channels # # drivers/i2c/chips/w83627hf.c # 2005/01/27 11:06:01-08:00 khali@linux-fr.org +21 -0 # I2C: Enable w83781d and w83627hf temperature channels # # ChangeSet # 2005/01/31 10:29:22-08:00 aurelien@aurel32.net # [PATCH] I2C: lm78 driver improvement # # The following patch against kernel 2.6.11-rc2-mm1 improves the lm78 # driver. I used it as a model to port the sis5595 driver to the 2.6 # kernel, and I then applied the changes suggested by Jean Delvare on # the sis5595 driver to this one. # # # Signed-off-by: Aurelien Jarno # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/lm78.c # 2005/01/25 13:26:01-08:00 aurelien@aurel32.net +24 -29 # I2C: lm78 driver improvement # # ChangeSet # 2005/01/24 22:28:35-08:00 khali@linux-fr.org # [PATCH] I2C: Fix i2c-sis5595 pci configuration accesses # # The i2c-sis5595 bus driver has logic errors on pci configuration # accesses. It returns an error on success and vice versa. The 2.4 kernel # version of the driver, as found in the lm_sensors CVS repository, is # correct, so the problem was introducted when the driver was ported to # the 2.6 kernel tree (in 2.6.0-test6). As odd as it sounds, the driver # has been sitting here broken and unusable for 17 months and nobody ever # reported, until yesterday. # # Credits go to Sebastian Hesselbarth for discovering and analyzing the # problem. # # Here is a patch that fixes the problem, succesfully tested by Aurelien # Jarno and Sebastian Hesselbarth. Please apply. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/busses/i2c-sis5595.c # 2005/01/22 09:55:09-08:00 khali@linux-fr.org +10 -5 # I2C: Fix i2c-sis5595 pci configuration accesses # # ChangeSet # 2005/01/24 22:28:20-08:00 mhoffman@lightlink.com # [PATCH] I2C: i2c-dev namespace cleanup # # This patch is namespace cleanup for the i2c-dev module. Please apply. # # Signed-off-by Mark M. Hoffman # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/i2c-dev.c # 2005/01/22 10:00:52-08:00 mhoffman@lightlink.com +4 -4 # I2C: i2c-dev namespace cleanup # # ChangeSet # 2005/01/24 22:27:54-08:00 khali@linux-fr.org # [PATCH] I2C: Reduce it87 i2c address range # # IT87xxF chips were never seen at any other I2C address than the default # (0x2d) so I think that we could safely reduce the range of addresses the # it87 drivers accepts. Currently it accepts 0x20-0x2f, I believe that # 0x28-0x2f would already be more than sufficient. # # (In theory, any address is possible, so whatever range we choose is # arbitrary anyway.) # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/it87.c # 2005/01/22 07:25:41-08:00 khali@linux-fr.org +4 -6 # I2C: Reduce it87 i2c address range # # ChangeSet # 2005/01/24 22:27:21-08:00 khali@linux-fr.org # [PATCH] I2C: Use standard temperature converters for as99127f # # When support for the Asus AS99127F chip was once added to the w83781d # driver, it was decided that we would treat temp2 and temp3 as having a # LSB of 0.25 degree C, as opposed to 0.5 degree C for the compatible # Winbond chips. The reason why this was done seems to be a couple of # users reporting that these temperatures were reading twice as high as it # should for them in the first place. We had much more feedback about the # A99127F chip since, and it turns out that the exact conversion required # for temp2 and temp3 depends on the motherboard model. For some models # (including my A7V133-C), we now have to multiply the readings by 2, # effectively negating the change that was once done in the driver. For # other models, a linear conversion formula is needed. The bottom line is # that the raw readings from the driver are correct for no known board, # while it would be for at least some of them if we had kept the same LSB # as the Winbond chips are known to have. Thus I believe that the standard # LSB of 0.5 degree C should be restored. # # There is no datasheet available for the AS99127F chip, so whatever was # done was guess work (and still is). I see no reason why we would keep # additional code in the w83781d driver to handle this former supposed # difference, especially when the facts now tend to prove that this # difference doesn't exist. # # The following patch drops the additional code and treats temp2 and temp3 # the same way for all chips supported by the w83781d driver. A similar # change will be made to the 2.4 version of this driver, and the default # sensors.conf will be updated accordingly. Users will have to update # their configuration file, or their readings will of course read twice as # high as they should due to the old conversion formulae. # # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/w83781d.c # 2005/01/21 11:54:05-08:00 khali@linux-fr.org +3 -17 # I2C: Use standard temperature converters for as99127f # # ChangeSet # 2005/01/24 22:26:49-08:00 nacc@us.ibm.com # [PATCH] w1/w1_therm: replace schedule_timeout() with msleep_interruptible() # # Description: Use msleep_interruptible() instead of schedule_timeout() to # guarantee the task delays as expected. Changed tm to an int, as it now is in # terms of msecs, not jiffies. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Evgeniy Polyakov # Signed-off-by: Greg Kroah-Hartman # # drivers/w1/w1_therm.c # 2005/01/21 13:41:08-08:00 nacc@us.ibm.com +4 -6 # w1/w1_therm: replace schedule_timeout() with msleep_interruptible() # # ChangeSet # 2005/01/24 22:20:22-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/superio/scx.c # 2005/01/21 10:39:02-08:00 johnpol@2ka.mipt.ru +5 -5 # superio: Use msleep* calls instead of direct schedule* calls. # # drivers/superio/sc.c # 2005/01/21 10:38:36-08:00 johnpol@2ka.mipt.ru +10 -10 # superio: Use msleep* calls instead of direct schedule* calls. # # drivers/superio/pc8736x.c # 2005/01/21 10:37:37-08:00 johnpol@2ka.mipt.ru +5 -5 # superio: Use msleep* calls instead of direct schedule* calls. # # ChangeSet # 2005/01/24 22:17:01-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/superio/scx.h # 2005/01/24 11:06:15-08:00 johnpol@2ka.mipt.ru +1 -1 # superio: change scx200 module name to scx. # # drivers/superio/scx.c # 2005/01/24 11:06:15-08:00 johnpol@2ka.mipt.ru +2 -2 # superio: change scx200 module name to scx. # # drivers/superio/Makefile # 2005/01/24 11:58:30-08:00 johnpol@2ka.mipt.ru +1 -1 # superio: change scx200 module name to scx. # # ChangeSet # 2005/01/24 22:15:33-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 # Signed-off-by: Greg Kroah-Hartman # # drivers/superio/sc_gpio.h # 2005/01/24 06:10:27-08:00 johnpol@2ka.mipt.ru +0 -7 # superio: remove unneded exports and make some functions static. # # drivers/superio/sc_gpio.c # 2005/01/24 06:10:45-08:00 johnpol@2ka.mipt.ru +16 -14 # superio: remove unneded exports and make some functions static. # # drivers/superio/sc_acb.c # 2005/01/24 06:09:35-08:00 johnpol@2ka.mipt.ru +10 -15 # superio: remove unneded exports and make some functions static. # # ChangeSet # 2005/01/20 13:23:14-08:00 khali@linux-fr.org # [PATCH] I2C: Resolve resource conflict between i2c-viapro and # # Here comes the finalized version of our patch solving the PCI device # resource conflict between the i2c-viapro bus driver and and the via686a # chip driver. It is based on your original work and the IRC conversation # we had yesterday. # # The retained solution is to not permanently register the PCI device in # either driver. This is legitimate since we only need it at init time to # retrieve the ISA address of a sub-device (SMBus master or integrated # sensors), and possibly change that address on user request. Once this is # done we can safely release the PCI device for others to use. # # I am really glad to see this problem finally solved, as this was the # last remaining annoying issue left from the Linux 2.6 migration (missing # drivers left apart), and was generating many complaints both at our # level and at the distributions' support. # # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/via686a.c # 2005/01/15 01:42:32-08:00 khali@linux-fr.org +17 -8 # I2C: Resolve resource conflict between i2c-viapro and # # drivers/i2c/busses/i2c-viapro.c # 2005/01/15 03:03:54-08:00 khali@linux-fr.org +19 -8 # I2C: Resolve resource conflict between i2c-viapro and # # ChangeSet # 2005/01/20 11:31:01-08:00 stefan@desire.ch # [PATCH] I2C: fix for fscpos voltage values # # Multiplied the voltage multipliers by 10 in order to comply with the sysfs # guidelines. # # Signed-off-by: Stefan Ott # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/fscpos.c # 2005/01/20 10:28:37-08:00 stefan@desire.ch +3 -3 # I2C: fix for fscpos voltage values # # ChangeSet # 2005/01/20 09:32:31-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 # Signed-off-by: Greg Kroah-Hartman # # lib/kobject_uevent.c # 2005/01/12 13:34:05-08:00 johnpol@2ka.mipt.ru +66 -0 # Re: kobject_uevent.c moved to kernel connector. # # ChangeSet # 2005/01/20 09:24:27-08:00 greg@kroah.com # [PATCH] superio: fix up some sparse warnings in the code # # Signed-off-by: Greg Kroah-Hartman # # drivers/superio/scx200.c # 2005/01/20 09:22:49-08:00 greg@kroah.com +5 -5 # superio: fix up some sparse warnings in the code # # drivers/superio/sc_gpio.c # 2005/01/20 09:22:49-08:00 greg@kroah.com +1 -1 # superio: fix up some sparse warnings in the code # # drivers/superio/pc8736x.c # 2005/01/20 09:22:49-08:00 greg@kroah.com +6 -6 # superio: fix up some sparse warnings in the code # # ChangeSet # 2005/01/20 09:24:02-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 # Signed-off-by: Greg Kroah-Hartman # # include/linux/sc_conn.h # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +50 -0 # superio: add SuperIO subsystem. # # drivers/superio/scx200.h # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +28 -0 # superio: add SuperIO subsystem. # # drivers/superio/scx200.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +413 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc_w1.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +107 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc_gpio.h # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +57 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc_gpio.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +310 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc_conn.c # 2005/01/19 23:53:24-08:00 johnpol@2ka.mipt.ru +124 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc_acb.h # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +45 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc_acb.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +163 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc.h # 2005/01/20 00:05:50-08:00 johnpol@2ka.mipt.ru +134 -0 # superio: add SuperIO subsystem. # # drivers/superio/sc.c # 2005/01/20 00:05:50-08:00 johnpol@2ka.mipt.ru +780 -0 # superio: add SuperIO subsystem. # # drivers/superio/pin_test.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +93 -0 # superio: add SuperIO subsystem. # # drivers/superio/pc8736x.h # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +39 -0 # superio: add SuperIO subsystem. # # drivers/superio/pc8736x.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +209 -0 # superio: add SuperIO subsystem. # # drivers/superio/chain.h # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +37 -0 # superio: add SuperIO subsystem. # # drivers/superio/Makefile # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +11 -0 # superio: add SuperIO subsystem. # # drivers/superio/Kconfig # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +56 -0 # superio: add SuperIO subsystem. # # include/linux/sc_conn.h # 2005/01/19 23:49:22-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/01/20 00:29:48-08:00 johnpol@2ka.mipt.ru +4 -1 # superio: add SuperIO subsystem. # # drivers/superio/scx200.h # 2005/01/19 23:49:22-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/01/19 23:49:22-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/01/19 23:49:22-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/01/19 23:49:22-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/01/19 23:49:22-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/01/19 23:53:24-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/01/19 23:49:22-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/01/19 23:49:22-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/01/20 00:05:50-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/01/20 00:05:50-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/01/19 23:49:22-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/01/19 23:49:22-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/01/19 23:49:22-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/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/chain.h # # drivers/superio/Makefile # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/Makefile # # drivers/superio/Kconfig # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/Kconfig # # drivers/Makefile # 2005/01/12 12:59:34-08:00 johnpol@2ka.mipt.ru +1 -0 # superio: add SuperIO subsystem. # # drivers/Kconfig # 2005/01/12 12:59:20-08:00 johnpol@2ka.mipt.ru +2 -0 # superio: add SuperIO subsystem. # # drivers/superio/chain.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +52 -0 # superio: add SuperIO subsystem. # # drivers/superio/chain.c # 2005/01/19 23:49:22-08:00 johnpol@2ka.mipt.ru +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/superio/chain.c # # ChangeSet # 2005/01/19 15:37:18-08:00 greg@kroah.com # [PATCH] I2C: just delete the id field, let's not delay it any longer # # Becides, sparse keeps complaining when it sees this attribute within a structure... # # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c.h # 2005/01/19 15:32:58-08:00 greg@kroah.com +0 -1 # I2C: just delete the id field, let's not delay it any longer # # ChangeSet # 2005/01/19 15:36:53-08:00 khali@linux-fr.org # [PATCH] I2C: Kill i2c_client.id (5/5) # # > (5/5) Documentation update. # # Finally, updates are required to the i2c/writing-client and # i2c/porting-client documents. Remove any reference to i2c_client id and # invite porters to discard that struct member. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # Documentation/i2c/writing-clients # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (5/5) # # Documentation/i2c/porting-clients # 2005/01/16 09:33:55-08:00 khali@linux-fr.org +3 -3 # I2C: Kill i2c_client.id (5/5) # # ChangeSet # 2005/01/19 15:36:30-08:00 khali@linux-fr.org # [PATCH] I2C: Kill i2c_client.id (4/5) # # > (4/5) Deprecate i2c_client.id. # # Now that i2c_client.id has no more users in the kernel (none that I # could find at least) we could remove that struct member. I however think # that it's better to only deprecate it at the moment, in case I missed # users or any of the other patches are delayed for some reason. We could # then delete the id member definitely in a month or so. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # include/linux/i2c.h # 2005/01/16 09:41:51-08:00 khali@linux-fr.org +1 -1 # I2C: Kill i2c_client.id (4/5) # # ChangeSet # 2005/01/19 15:35:35-08:00 khali@linux-fr.org # [PATCH] I2C: Kill i2c_client.id (3/5) # # (3/5) Stop using i2c_client.id in misc drivers. # # Affected drivers: # * acorn/char/pcf8583 # * acorn/char/i2c # * i2c/i2c-dev # * macintosh/therm_windtunnel # * sound/oss/dmasound/dac3550a # * sound/ppc/keywest # # The Acorn pcf8583 driver would give the i2c_client id the same value as # the i2c_driver id, and later test that client id (in i2c). I changed it # to test the client's driver id instead. The result is the same and the # client id is then useless and can be removed. # # All other drivers here would allocate the client id to some value and # then never use it. They are unaffected by the change. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # sound/ppc/keywest.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -2 # I2C: Kill i2c_client.id (3/5) # # sound/oss/dmasound/dac3550a.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (3/5) # # drivers/macintosh/therm_windtunnel.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (3/5) # # drivers/i2c/i2c-dev.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (3/5) # # drivers/acorn/char/pcf8583.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (3/5) # # drivers/acorn/char/i2c.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -1 # I2C: Kill i2c_client.id (3/5) # # ChangeSet # 2005/01/19 15:35:01-08:00 khali@linux-fr.org # [PATCH] I2C: Kill i2c_client.id (2/5) # # (2/5) Stop using i2c_client.id in media/video drivers. # # Affected drivers: # * adv7170 # * adv7175 # * bt819 # * bt856 # * bttv # * cx88 # * ovcamchip # * saa5246a # * saa5249 # * saa7110 # * saa7111 # * saa7114 # * saa7134 # * saa7185 # * tda7432 # * tda9840 # * tda9875 # * tea6415c # * tea6420 # * tuner-3036 # * vpx3220 # # Most drivers here would include the id as part of their i2c client name # (e.g. adv7170[0]). This looks more like an habit than something really # needed, so I replaced the various printf by strlcpy, which should be # slightly faster. As said earlier, clients can be differenciated thanks # to their bus id and address if needed, so I don't think that including # this information in the client name is wise anyway. # # Other drivers would either set the id to -1 or to a unique value but # then never use it. These drivers are unaffected by the changes. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/media/video/vpx3220.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +8 -11 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/tuner-3036.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/tea6420.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/tea6415c.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/tda9875.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/tda9840.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/tda7432.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa7185.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa7134/saa7134-i2c.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa7114.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa7111.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa7110.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa5249.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/saa5246a.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/ovcamchip/ovcamchip_core.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/cx88/cx88-i2c.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/bttv-i2c.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/bt856.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/bt819.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +3 -8 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/adv7175.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # drivers/media/video/adv7170.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +1 -4 # I2C: Kill i2c_client.id (2/5) # # ChangeSet # 2005/01/19 15:34:03-08:00 khali@linux-fr.org # [PATCH] I2C: Kill i2c_client.id (1/5) # # (1/5) Stop using i2c_client.id in i2c/chips drivers (mostly hardware # monitoring drivers). # # Drivers affected: # * adm1021 # * adm1025 # * adm1026 # * adm1031 # * ds1621 # * fscher # * gl518sm # * isp1301_omap # * lm75 # * lm77 # * lm80 # * lm83 # * lm85 # * lm87 # * lm90 # * max1619 # * pcf8574 # * pcf8591 # * rtc8564 # * smsc47m1 # * w83l785ts # # The vast majority of these drivers simply defined the i2c_client id # struct member but never used it, so they are not affected at all by the # change. Exceptions are: # # * lm85 and rtc8564, which would at least display the id in a debug # message when assigning it. Not really useful though, as the id was then # never used. # # * adm1026, which used the assigned id in all driver messages. However, # since dev_* calls will append the bus number and client address to these # messages, the id information is redundant and can go away. Also, the # driver would allow some GPIO reprogramming on the first client only # (id=0) and removing the id doesn't allow that anymore. I would restore a # similar functionality if needed, but the ADM1026 chip is found on very # few motherboards and none of these has more than one ADM1026 chip AFAIK, # so it doesn't seem to be worth the effort. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/w83l785ts.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/smsc47m1.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -5 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/rtc8564.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -2 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/pcf8591.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/pcf8574.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/max1619.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm90.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm87.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm85.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -9 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm83.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm80.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -8 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm77.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/lm75.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/isp1301_omap.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -1 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/gl518sm.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/fscher.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/ds1621.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/adm1031.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/adm1026.c # 2005/01/16 03:52:45-08:00 khali@linux-fr.org +32 -48 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/adm1025.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -7 # I2C: Kill i2c_client.id (1/5) # # drivers/i2c/chips/adm1021.c # 2005/01/16 03:50:29-08:00 khali@linux-fr.org +0 -4 # I2C: Kill i2c_client.id (1/5) # # ChangeSet # 2005/01/19 15:20:48-08:00 greg@kroah.com # [PATCH] I2C: Fix up some build warnings in the fscpos driver. # # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/fscpos.c # 2005/01/19 15:18:59-08:00 greg@kroah.com +1 -3 # I2C: Fix up some build warnings in the fscpos driver. # # ChangeSet # 2005/01/19 15:20:28-08:00 khali@linux-fr.org # [PATCH] I2C: Allow it87 pwm reconfiguration # # Quoting myself: # # > As soon as you will have confirmed that everything worked as expected, # > Jonas and I will provide a patch adding a pwm polarity reconfiguration # > module parameter for you to test. This should give you access to the # > PWM features of your it87 chip again, but in a safe way for a change # > ;) # # Here comes this patch. The new "fix_pwm_polarity" module parameter # allows one to force the it87 chip reconfiguration. This is only # supported in the case the original PWM configuration is suspected to be # bogus, and only if we think that reconfiguring the chip is safe. # # I wish to thank Rudolf Marek and Jonas Munsin again for their testing # and review of my code. # # Signed-off-by: Jean Delvare # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/it87.c # 2005/01/15 06:46:04-08:00 khali@linux-fr.org +59 -12 # I2C: Allow it87 pwm reconfiguration # # ChangeSet # 2005/01/19 15:20:07-08:00 stefan@desire.ch # [PATCH] fscpos driver # # This patch against 2.6.11-rc1 contains a driver for fscpos sensors. # # Signed-off-by: Stefan Ott # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/fscpos.c # 2005/01/19 10:12:57-08:00 stefan@desire.ch +633 -0 # fscpos driver # # drivers/i2c/chips/Makefile # 2005/01/19 12:03:07-08:00 stefan@desire.ch +1 -0 # fscpos driver # # drivers/i2c/chips/Kconfig # 2005/01/19 12:03:07-08:00 stefan@desire.ch +11 -0 # fscpos driver # # drivers/i2c/chips/fscpos.c # 2005/01/19 10:12:57-08:00 stefan@desire.ch +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/i2c/chips/fscpos.c # # ChangeSet # 2005/01/19 15:19:45-08:00 aurelien@aurel32.net # [PATCH] I2C: Fix DS1621 detection # # Dallas Semiconductors as recently changed the design of their DS1621 # chips, including the bits that were checked in the kernel driver to # detect it. # # The patch below fixes the detection by checking an other bit of the # configuration register instead. # # Signed-off-by: Aurelien Jarno # Signed-off-by: Greg Kroah-Hartman # # drivers/i2c/chips/ds1621.c # 2005/01/19 09:39:23-08:00 aurelien@aurel32.net +8 -4 # I2C: Fix DS1621 detection # # ChangeSet # 2005/01/19 14:34:32-08:00 johnpol@2ka.mipt.ru # [PATCH] Add Kernel conector subsystem # # Signed-off-by: Evgeniy Polyakov # Signed-off-by: Greg Kroah-Hartman # # include/linux/connector.h # 2005/01/12 13:53:21-08:00 johnpol@2ka.mipt.ru +147 -0 # Add Kernel conector subsystem # # drivers/connector/connector.c # 2005/01/13 05:25:50-08:00 johnpol@2ka.mipt.ru +509 -0 # Add Kernel conector subsystem # # drivers/connector/cn_queue.c # 2005/01/13 05:26:41-08:00 johnpol@2ka.mipt.ru +219 -0 # Add Kernel conector subsystem # # drivers/connector/Makefile # 2005/01/12 13:14:47-08:00 johnpol@2ka.mipt.ru +2 -0 # Add Kernel conector subsystem # # include/linux/connector.h # 2005/01/12 13:53:21-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/01/13 05:25:50-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/01/13 05:26:41-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/01/12 13:14:47-08:00 johnpol@2ka.mipt.ru +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/connector/Makefile # # drivers/Makefile # 2005/01/12 12:25:28-08:00 johnpol@2ka.mipt.ru +2 -0 # Add Kernel conector subsystem # # drivers/Kconfig # 2005/01/12 12:25:49-08:00 johnpol@2ka.mipt.ru +2 -0 # Add Kernel conector subsystem # # drivers/connector/Kconfig # 2005/01/12 13:14:47-08:00 johnpol@2ka.mipt.ru +13 -0 # Add Kernel conector subsystem # # drivers/connector/Kconfig # 2005/01/12 13:14:47-08:00 johnpol@2ka.mipt.ru +0 -0 # BitKeeper file /home/greg/linux/BK/i2c-2.6/drivers/connector/Kconfig # diff -Nru a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients --- a/Documentation/i2c/porting-clients 2005-02-28 17:20:43 -08:00 +++ b/Documentation/i2c/porting-clients 2005-02-28 17:20:43 -08:00 @@ -49,9 +49,8 @@ static void lm75_update_client(struct i2c_client *client); * [Sysctl] All sysctl stuff is of course gone (defines, ctl_table - and functions). Instead, right after the static id definition - line, you have to define show and set functions for each sysfs - file. Only define set for writable values. Take a look at an + and functions). Instead, you have to define show and set functions for + each sysfs file. Only define set for writable values. Take a look at an existing 2.6 driver for details (lm78 for example). Don't forget to define the attributes for each file (this is that step that links callback functions). Use the file names specified in @@ -86,6 +85,7 @@ Replace the sysctl directory registration by calls to device_create_file. Move the driver initialization before any sysfs file creation. + Drop client->id. * [Init] Limits must not be set by the driver (can be done later in user-space). Chip should not be reset default (although a module diff -Nru a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients --- a/Documentation/i2c/writing-clients 2005-02-28 17:20:43 -08:00 +++ b/Documentation/i2c/writing-clients 2005-02-28 17:20:43 -08:00 @@ -344,9 +344,6 @@ For now, you can ignore the `flags' parameter. It is there for future use. - /* Unique ID allocation */ - static int foo_id = 0; - int foo_detect_client(struct i2c_adapter *adapter, int address, unsigned short flags, int kind) { @@ -482,7 +479,6 @@ data->type = kind; /* SENSORS ONLY END */ - new_client->id = foo_id++; /* Automatically unique */ data->valid = 0; /* Only if you use this field */ init_MUTEX(&data->update_lock); /* Only if you use this field */ @@ -642,7 +638,7 @@ parameter contains the bytes the read/write, the third the length of the buffer. Returned is the actual number of bytes read/written. - extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num); This sends a series of messages. Each message can be a read or write, diff -Nru a/drivers/Kconfig b/drivers/Kconfig --- a/drivers/Kconfig 2005-02-28 17:20:43 -08:00 +++ b/drivers/Kconfig 2005-02-28 17:20:43 -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-02-28 17:20:43 -08:00 +++ b/drivers/Makefile 2005-02-28 17:20:43 -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/acorn/char/i2c.c b/drivers/acorn/char/i2c.c --- a/drivers/acorn/char/i2c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/acorn/char/i2c.c 2005-02-28 17:20:43 -08:00 @@ -313,7 +313,7 @@ static int ioc_client_reg(struct i2c_client *client) { - if (client->id == I2C_DRIVERID_PCF8583 && + if (client->driver->id == I2C_DRIVERID_PCF8583 && client->addr == 0x50) { struct rtc_tm rtctm; unsigned int year; diff -Nru a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c --- a/drivers/acorn/char/pcf8583.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/acorn/char/pcf8583.c 2005-02-28 17:20:43 -08:00 @@ -51,7 +51,6 @@ return -ENOMEM; memset(c, 0, sizeof(*c)); - c->id = pcf8583_driver.id; c->addr = addr; c->adapter = adap; c->driver = &pcf8583_driver; diff -Nru a/drivers/connector/Kconfig b/drivers/connector/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/connector/Kconfig 2005-02-28 17:20:43 -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-02-28 17:20:43 -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-02-28 17:20:43 -08:00 @@ -0,0 +1,231 @@ +/* + * cn_queue.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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-02-28 17:20:43 -08:00 @@ -0,0 +1,521 @@ +/* + * connector.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include +#include +#include +#include +#include + +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +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 (msg->len != nlh->nlmsg_len - sizeof(*msg) - sizeof(*nlh)) { + printk(KERN_ERR "skb does not have enough length: " + "requested msg->len=%u[%u], nlh->nlmsg_len=%u[%u], skb->len=%u[must be %u].\n", + msg->len, NLMSG_SPACE(msg->len), + nlh->nlmsg_len, nlh->nlmsg_len - sizeof(*nlh), + skb->len, msg->len + sizeof(*msg)); + 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(¬ify_lock); + list_for_each_entry(ent, ¬ify_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; iidx_notify_num; ++i, ++req) { + if (id->idx >= req->first && id->idx < req->first + req->range) { + a = 1; + break; + } + } + + for (i=0; ival_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(¬ify_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; iidx_notify_num; ++i) { + if (memcmp(req1, req2, sizeof(*req1))) + return 0; + + req1++; + req2++; + } + + for (i=0; ival_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(¬ify_lock); + list_for_each_entry_safe(ent, n, ¬ify_list, notify_entry) { + if (cn_ctl_msg_equals(ent->msg, ctl)) { + list_del(&ent->notify_entry); + kfree(ent); + } + } + spin_unlock_bh(¬ify_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(¬ify_lock); + list_add(&ent->notify_entry, ¬ify_list); + spin_unlock_bh(¬ify_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; iidx_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; ival_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-02-28 17:20:43 -08:00 +++ b/drivers/i2c/algos/i2c-algo-ite.c 2005-02-28 17:20:43 -08:00 @@ -490,7 +490,7 @@ * condition. */ #if 0 -static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { int i; struct i2c_msg *pmsg; @@ -600,7 +600,7 @@ * verify that the bus is not busy or in some unknown state. */ static int iic_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct i2c_algo_iic_data *adap = i2c_adap->algo_data; diff -Nru a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c --- a/drivers/i2c/algos/i2c-algo-pca.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/algos/i2c-algo-pca.c 2005-02-28 17:20:43 -08:00 @@ -178,7 +178,7 @@ } static int pca_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct i2c_algo_pca_data *adap = i2c_adap->algo_data; @@ -186,6 +186,7 @@ int curmsg; int numbytes = 0; int state; + int ret; state = pca_status(adap); if ( state != 0xF8 ) { @@ -218,6 +219,7 @@ } curmsg = 0; + ret = -EREMOTEIO; while (curmsg < num) { state = pca_status(adap); @@ -251,7 +253,7 @@ case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */ DEB2("NOT ACK received after SLA+W\n"); pca_stop(adap); - return -EREMOTEIO; + goto out; case 0x40: /* SLA+R has been transmitted; ACK has been received */ pca_rx_ack(adap, msg->len > 1); @@ -263,7 +265,7 @@ numbytes++; pca_rx_ack(adap, numbytes < msg->len - 1); break; - } + } curmsg++; numbytes = 0; if (curmsg == num) pca_stop(adap); @@ -274,15 +276,15 @@ case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */ DEB2("NOT ACK received after SLA+R\n"); pca_stop(adap); - return -EREMOTEIO; + goto out; case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */ DEB2("NOT ACK received after data byte\n"); - return -EREMOTEIO; + goto out; case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */ DEB2("Arbitration lost\n"); - return -EREMOTEIO; + goto out; case 0x58: /* Data byte has been received; NOT ACK has been returned */ if ( numbytes == msg->len - 1 ) { @@ -297,21 +299,21 @@ "Not final byte. numbytes %d. len %d\n", numbytes, msg->len); pca_stop(adap); - return -EREMOTEIO; + goto out; } break; case 0x70: /* Bus error - SDA stuck low */ DEB2("BUS ERROR - SDA Stuck low\n"); pca_reset(adap); - return -EREMOTEIO; + goto out; case 0x90: /* Bus error - SCL stuck low */ DEB2("BUS ERROR - SCL Stuck low\n"); pca_reset(adap); - return -EREMOTEIO; + goto out; case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */ DEB2("BUS ERROR - Illegal START or STOP\n"); pca_reset(adap); - return -EREMOTEIO; + goto out; default: printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state); break; @@ -319,11 +321,13 @@ } - DEB1(KERN_CRIT "}}} transfered %d messages. " + ret = curmsg; + out: + DEB1(KERN_CRIT "}}} transfered %d/%d messages. " "status is %#04x. control is %#04x\n", - num, pca_status(adap), + curmsg, num, pca_status(adap), pca_get_con(adap)); - return curmsg; + return ret; } static u32 pca_func(struct i2c_adapter *adap) 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-02-28 17:20:43 -08:00 +++ b/drivers/i2c/algos/i2c-algo-pcf.c 2005-02-28 17:20:43 -08:00 @@ -332,7 +332,7 @@ } static int pcf_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; diff -Nru a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c --- a/drivers/i2c/algos/i2c-algo-sgi.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/algos/i2c-algo-sgi.c 2005-02-28 17:20:43 -08:00 @@ -131,7 +131,7 @@ return 0; } -static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], +static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_algo_sgi_data *adap = i2c_adap->algo_data; diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig --- a/drivers/i2c/busses/Kconfig 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/Kconfig 2005-02-28 17:20:43 -08:00 @@ -287,7 +287,7 @@ config I2C_PIIX4 tristate "Intel PIIX4" - depends on I2C && PCI && EXPERIMENTAL && !64BIT + 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 @@ -485,5 +485,15 @@ This driver can also be built as a module. If so, the module will be called i2c-pca-isa. + +config I2C_MV64XXX + tristate "Marvell mv64xxx I2C Controller" + depends on I2C && MV64X60 && EXPERIMENTAL + help + If you say yes to this option, support will be included for the + built-in I2C interface on the Marvell 64xxx line of host bridges. + + This driver can also be built as a module. If so, the module + will be called i2c-mv64xxx. endmenu diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile --- a/drivers/i2c/busses/Makefile 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/Makefile 2005-02-28 17:20:43 -08:00 @@ -21,6 +21,7 @@ obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o +obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o diff -Nru a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c --- a/drivers/i2c/busses/i2c-au1550.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-au1550.c 2005-02-28 17:20:43 -08:00 @@ -253,7 +253,7 @@ } static int -au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_au1550_data *adap = i2c_adap->algo_data; struct i2c_msg *p; diff -Nru a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c --- a/drivers/i2c/busses/i2c-elektor.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-elektor.c 2005-02-28 17:20:43 -08:00 @@ -183,6 +183,7 @@ static struct i2c_adapter pcf_isa_ops = { .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, .id = I2C_HW_P_ELEK, .algo_data = &pcf_isa_data, .name = "PCF8584 ISA adapter", 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-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-ibm_iic.c 2005-02-28 17:20:43 -08:00 @@ -549,7 +549,7 @@ * Generic master transfer entrypoint. * Returns the number of processed messages or error (<0) */ -static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap)); volatile struct iic_regs __iomem *iic = dev->vaddr; diff -Nru a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c --- a/drivers/i2c/busses/i2c-iop3xx.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-iop3xx.c 2005-02-28 17:20:43 -08:00 @@ -361,7 +361,7 @@ * master_xfer() - main read/write entry */ static int -iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], +iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; diff -Nru a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c --- a/drivers/i2c/busses/i2c-ixp4xx.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-ixp4xx.c 2005-02-28 17:20:43 -08:00 @@ -133,8 +133,8 @@ drv_data->algo_data.mdelay = 10; drv_data->algo_data.timeout = 100; - drv_data->adapter.id = I2C_HW_B_IXP4XX, - drv_data->adapter.algo_data = &drv_data->algo_data, + drv_data->adapter.id = I2C_HW_B_IXP4XX; + drv_data->adapter.algo_data = &drv_data->algo_data; drv_data->adapter.dev.parent = &plat_dev->dev; diff -Nru a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c --- a/drivers/i2c/busses/i2c-keywest.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-keywest.c 2005-02-28 17:20:43 -08:00 @@ -399,7 +399,7 @@ */ static int keywest_xfer( struct i2c_adapter *adap, - struct i2c_msg msgs[], + struct i2c_msg *msgs, int num) { struct keywest_chan* chan = i2c_get_adapdata(adap); diff -Nru a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c --- a/drivers/i2c/busses/i2c-mpc.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-mpc.c 2005-02-28 17:20:43 -08:00 @@ -233,7 +233,7 @@ return length; } -static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *pmsg; int i; diff -Nru a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/busses/i2c-mv64xxx.c 2005-02-28 17:20:43 -08:00 @@ -0,0 +1,596 @@ +/* + * drivers/i2c/busses/i2c-mv64xxx.c + * + * Driver for the i2c controller on the Marvell line of host bridges for MIPS + * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0). + * + * Author: Mark A. Greer + * + * 2005 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include +#include +#include +#include +#include +#include +#include + +/* Register defines */ +#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 +#define MV64XXX_I2C_REG_DATA 0x04 +#define MV64XXX_I2C_REG_CONTROL 0x08 +#define MV64XXX_I2C_REG_STATUS 0x0c +#define MV64XXX_I2C_REG_BAUD 0x0c +#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10 +#define MV64XXX_I2C_REG_SOFT_RESET 0x1c + +#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004 +#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008 +#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010 +#define MV64XXX_I2C_REG_CONTROL_START 0x00000020 +#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040 +#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080 + +/* Ctlr status values */ +#define MV64XXX_I2C_STATUS_BUS_ERR 0x00 +#define MV64XXX_I2C_STATUS_MAST_START 0x08 +#define MV64XXX_I2C_STATUS_MAST_REPEAT_START 0x10 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 +#define MV64XXX_I2C_STATUS_MAST_WR_ACK 0x28 +#define MV64XXX_I2C_STATUS_MAST_WR_NO_ACK 0x30 +#define MV64XXX_I2C_STATUS_MAST_LOST_ARB 0x38 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 +#define MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK 0x50 +#define MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 +#define MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 +#define MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 +#define MV64XXX_I2C_STATUS_NO_STATUS 0xf8 + +/* Driver states */ +enum { + MV64XXX_I2C_STATE_INVALID, + MV64XXX_I2C_STATE_IDLE, + MV64XXX_I2C_STATE_WAITING_FOR_START_COND, + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA, + MV64XXX_I2C_STATE_ABORTING, +}; + +/* Driver actions */ +enum { + MV64XXX_I2C_ACTION_INVALID, + MV64XXX_I2C_ACTION_CONTINUE, + MV64XXX_I2C_ACTION_SEND_START, + MV64XXX_I2C_ACTION_SEND_ADDR_1, + MV64XXX_I2C_ACTION_SEND_ADDR_2, + MV64XXX_I2C_ACTION_SEND_DATA, + MV64XXX_I2C_ACTION_RCV_DATA, + MV64XXX_I2C_ACTION_RCV_DATA_STOP, + MV64XXX_I2C_ACTION_SEND_STOP, +}; + +struct mv64xxx_i2c_data { + int irq; + u32 state; + u32 action; + u32 cntl_bits; + void __iomem *reg_base; + u32 reg_base_p; + u32 addr1; + u32 addr2; + u32 bytes_left; + u32 byte_posn; + u32 block; + int rc; + u32 freq_m; + u32 freq_n; + wait_queue_head_t waitq; + spinlock_t lock; + struct i2c_msg *msg; + struct i2c_adapter adapter; +}; + +/* + ***************************************************************************** + * + * Finite State Machine & Interrupt Routines + * + ***************************************************************************** + */ +static void +mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) +{ + /* + * If state is idle, then this is likely the remnants of an old + * operation that driver has given up on or the user has killed. + * If so, issue the stop condition and go to idle. + */ + if (drv_data->state == MV64XXX_I2C_STATE_IDLE) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + return; + } + + if (drv_data->state == MV64XXX_I2C_STATE_ABORTING) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + return; + } + + /* The status from the ctlr [mostly] tells us what to do next */ + switch (status) { + /* Start condition interrupt */ + case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */ + case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */ + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; + break; + + /* Performing a write */ + case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */ + if (drv_data->msg->flags & I2C_M_TEN) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; + break; + } + /* FALLTHRU */ + case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */ + case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */ + if (drv_data->bytes_left > 0) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; + drv_data->bytes_left--; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + } + break; + + /* Performing a read */ + case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */ + if (drv_data->msg->flags & I2C_M_TEN) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK; + break; + } + /* FALLTHRU */ + case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */ + if (drv_data->bytes_left == 0) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + break; + } + /* FALLTHRU */ + case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */ + if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK) + drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; + else { + drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; + drv_data->bytes_left--; + } + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; + + if (drv_data->bytes_left == 1) + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; + break; + + case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ + drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + break; + + case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */ + case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */ + case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */ + /* Doesn't seem to be a device at other end */ + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + drv_data->rc = -ENODEV; + break; + + default: + dev_err(&drv_data->adapter.dev, + "mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " + "status: 0x%x, addr: 0x%x, flags: 0x%x\n", + drv_data->state, status, drv_data->msg->addr, + drv_data->msg->flags); + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + drv_data->rc = -EIO; + } +} + +static void +mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) +{ + switch(drv_data->action) { + case MV64XXX_I2C_ACTION_CONTINUE: + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_START: + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_ADDR_1: + writel(drv_data->addr1, + drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_ADDR_2: + writel(drv_data->addr2, + drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_SEND_DATA: + writel(drv_data->msg->buf[drv_data->byte_posn++], + drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_RCV_DATA: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + break; + + case MV64XXX_I2C_ACTION_RCV_DATA_STOP: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->block = 0; + wake_up_interruptible(&drv_data->waitq); + break; + + case MV64XXX_I2C_ACTION_INVALID: + default: + dev_err(&drv_data->adapter.dev, + "mv64xxx_i2c_do_action: Invalid action: %d\n", + drv_data->action); + drv_data->rc = -EIO; + /* FALLTHRU */ + case MV64XXX_I2C_ACTION_SEND_STOP: + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->block = 0; + wake_up_interruptible(&drv_data->waitq); + break; + } +} + +static int +mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mv64xxx_i2c_data *drv_data = dev_id; + unsigned long flags; + u32 status; + int rc = IRQ_NONE; + + spin_lock_irqsave(&drv_data->lock, flags); + while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) & + MV64XXX_I2C_REG_CONTROL_IFLG) { + status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS); + mv64xxx_i2c_fsm(drv_data, status); + mv64xxx_i2c_do_action(drv_data); + rc = IRQ_HANDLED; + } + spin_unlock_irqrestore(&drv_data->lock, flags); + + return rc; +} + +/* + ***************************************************************************** + * + * I2C Msg Execution Routines + * + ***************************************************************************** + */ +static void +mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, + struct i2c_msg *msg) +{ + u32 dir = 0; + + drv_data->msg = msg; + drv_data->byte_posn = 0; + drv_data->bytes_left = msg->len; + drv_data->rc = 0; + drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | + MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; + + if (msg->flags & I2C_M_RD) + dir = 1; + + if (msg->flags & I2C_M_REV_DIR_ADDR) + dir ^= 1; + + if (msg->flags & I2C_M_TEN) { + drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; + drv_data->addr2 = (u32)msg->addr & 0xff; + } else { + drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; + drv_data->addr2 = 0; + } +} + +static void +mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) +{ + long time_left; + unsigned long flags; + char abort = 0; + + time_left = wait_event_interruptible_timeout(drv_data->waitq, + !drv_data->block, msecs_to_jiffies(drv_data->adapter.timeout)); + + spin_lock_irqsave(&drv_data->lock, flags); + if (!time_left) { /* Timed out */ + drv_data->rc = -ETIMEDOUT; + abort = 1; + } else if (time_left < 0) { /* Interrupted/Error */ + drv_data->rc = time_left; /* errno value */ + abort = 1; + } + + if (abort && drv_data->block) { + drv_data->state = MV64XXX_I2C_STATE_ABORTING; + spin_unlock_irqrestore(&drv_data->lock, flags); + + time_left = wait_event_timeout(drv_data->waitq, + !drv_data->block, + msecs_to_jiffies(drv_data->adapter.timeout)); + + if (time_left <= 0) { + drv_data->state = MV64XXX_I2C_STATE_IDLE; + dev_err(&drv_data->adapter.dev, + "mv64xxx: I2C bus locked\n"); + } + } else + spin_unlock_irqrestore(&drv_data->lock, flags); +} + +static int +mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) +{ + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + mv64xxx_i2c_prepare_for_io(drv_data, msg); + + if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */ + if (drv_data->msg->flags & I2C_M_RD) { + /* No action to do, wait for slave to send a byte */ + drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; + drv_data->bytes_left--; + } + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + } + + drv_data->block = 1; + mv64xxx_i2c_do_action(drv_data); + spin_unlock_irqrestore(&drv_data->lock, flags); + + mv64xxx_i2c_wait_for_completion(drv_data); + return drv_data->rc; +} + +/* + ***************************************************************************** + * + * I2C Core Support Routines (Interface to higher level I2C code) + * + ***************************************************************************** + */ +static u32 +mv64xxx_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; +} + +static int +mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + int i, rc = 0; + + for (i=0; ireg_base + MV64XXX_I2C_REG_SOFT_RESET); + writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), + drv_data->reg_base + MV64XXX_I2C_REG_BAUD); + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); + writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->state = MV64XXX_I2C_STATE_IDLE; +} + +static int __devinit +mv64xxx_i2c_map_regs(struct platform_device *pd, + struct mv64xxx_i2c_data *drv_data) +{ + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) && + request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE, + drv_data->adapter.name)) { + + drv_data->reg_base = ioremap(r->start, + MV64XXX_I2C_REG_BLOCK_SIZE); + drv_data->reg_base_p = r->start; + } else + return -ENOMEM; + + return 0; +} + +static void __devexit +mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) +{ + if (drv_data->reg_base) { + iounmap(drv_data->reg_base); + release_mem_region(drv_data->reg_base_p, + MV64XXX_I2C_REG_BLOCK_SIZE); + } + + drv_data->reg_base = NULL; + drv_data->reg_base_p = 0; +} + +static int __devinit +mv64xxx_i2c_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct mv64xxx_i2c_data *drv_data; + struct mv64xxx_i2c_pdata *pdata = dev->platform_data; + int rc; + + if ((pd->id != 0) || !pdata) + return -ENODEV; + + drv_data = kmalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); + + if (!drv_data) + return -ENOMEM; + + memset(drv_data, 0, sizeof(struct mv64xxx_i2c_data)); + + if (mv64xxx_i2c_map_regs(pd, drv_data)) { + rc = -ENODEV; + goto exit_kfree; + } + + strncpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", + I2C_NAME_SIZE); + + init_waitqueue_head(&drv_data->waitq); + spin_lock_init(&drv_data->lock); + + drv_data->freq_m = pdata->freq_m; + drv_data->freq_n = pdata->freq_n; + drv_data->irq = platform_get_irq(pd, 0); + drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX; + drv_data->adapter.algo = &mv64xxx_i2c_algo; + drv_data->adapter.timeout = pdata->timeout; + drv_data->adapter.retries = pdata->retries; + dev_set_drvdata(dev, drv_data); + i2c_set_adapdata(&drv_data->adapter, drv_data); + + if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, + MV64XXX_I2C_CTLR_NAME, drv_data)) { + + dev_err(dev, "mv64xxx: Can't register intr handler " + "irq: %d\n", drv_data->irq); + rc = -EINVAL; + goto exit_unmap_regs; + } else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) { + dev_err(dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); + goto exit_free_irq; + } + + mv64xxx_i2c_hw_init(drv_data); + + return 0; + + exit_free_irq: + free_irq(drv_data->irq, drv_data); + exit_unmap_regs: + mv64xxx_i2c_unmap_regs(drv_data); + exit_kfree: + kfree(drv_data); + return rc; +} + +static int __devexit +mv64xxx_i2c_remove(struct device *dev) +{ + struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev); + int rc; + + rc = i2c_del_adapter(&drv_data->adapter); + free_irq(drv_data->irq, drv_data); + mv64xxx_i2c_unmap_regs(drv_data); + kfree(drv_data); + + return rc; +} + +static struct device_driver mv64xxx_i2c_driver = { + .name = MV64XXX_I2C_CTLR_NAME, + .bus = &platform_bus_type, + .probe = mv64xxx_i2c_probe, + .remove = mv64xxx_i2c_remove, +}; + +static int __init +mv64xxx_i2c_init(void) +{ + return driver_register(&mv64xxx_i2c_driver); +} + +static void __exit +mv64xxx_i2c_exit(void) +{ + driver_unregister(&mv64xxx_i2c_driver); +} + +module_init(mv64xxx_i2c_init); +module_exit(mv64xxx_i2c_exit); + +MODULE_AUTHOR("Mark A. Greer "); +MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c --- a/drivers/i2c/busses/i2c-nforce2.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-nforce2.c 2005-02-28 17:20:43 -08:00 @@ -29,9 +29,10 @@ nForce2 Ultra 400 MCP 0084 nForce3 Pro150 MCP 00D4 nForce3 250Gb MCP 00E4 + nForce4 MCP 0052 - This driver supports the 2 SMBuses that are included in the MCP2 of the - nForce2 chipset. + This driver supports the 2 SMBuses that are included in the MCP of the + nForce2/3/4 chipsets. */ /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ @@ -295,6 +296,7 @@ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) }, { 0 } }; diff -Nru a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c --- a/drivers/i2c/busses/i2c-s3c2410.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/busses/i2c-s3c2410.c 2005-02-28 17:20:43 -08:00 @@ -483,7 +483,7 @@ * this starts an i2c transfer */ -static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], int num) +static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { unsigned long timeout; int ret; @@ -534,7 +534,7 @@ */ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msgs[], int num) + struct i2c_msg *msgs, int num) { struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data; int retry; @@ -569,6 +569,7 @@ .name = "s3c2410-i2c", .algo = &s3c24xx_i2c_algorithm, .retries = 2, + .class = I2C_CLASS_HWMON, }, }; diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/Kconfig 2005-02-28 17:20:43 -08:00 @@ -84,6 +84,17 @@ This driver can also be built as a module. If so, the module will be called fscher. +config SENSORS_FSCPOS + tristate "FSC Poseidon" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Fujitsu Siemens + Computers Poseidon sensor chips. + + This driver can also be built as a module. If so, the module + will be called fscpos. + config SENSORS_GL518SM tristate "Genesys Logic GL518SM" depends on I2C && EXPERIMENTAL @@ -95,6 +106,17 @@ This driver can also be built as a module. If so, the module will be called gl518sm. +config SENSORS_GL520SM + tristate "Genesys Logic GL520SM" + depends on I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Genesys Logic GL520SM + sensor chips. + + This driver can also be built as a module. If so, the module + will be called gl520sm. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" depends on I2C && EXPERIMENTAL @@ -251,6 +273,18 @@ This driver can also be built as a module. If so, the module will be called smsc47b397. +config SENSORS_SIS5595 + tristate "Silicon Integrated Systems Corp. SiS5595" + depends on I2C && PCI && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated sensors in + SiS5595 South Bridges. + + This driver can also be built as a module. If so, the module + will be called sis5595. + config SENSORS_SMSC47M1 tristate "SMSC LPC47M10x and compatibles" depends on I2C && EXPERIMENTAL @@ -370,5 +404,14 @@ This driver can also be built as a module. If so, the module will be called isp1301_omap. + +config SENSORS_M41T00 + tristate "ST M41T00 RTC chip" + depends on I2C && PPC32 + help + If you say yes here you get support for the ST M41T00 RTC chip. + + This driver can also be built as a module. If so, the module + will be called m41t00. endmenu diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/Makefile 2005-02-28 17:20:43 -08:00 @@ -14,7 +14,9 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o +obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o +obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM75) += lm75.o @@ -26,10 +28,12 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o +obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o +obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/adm1021.c 2005-02-28 17:20:43 -08:00 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -147,8 +148,6 @@ .detach_client = adm1021_detach_client, }; -static int adm1021_id; - #define show(value) \ static ssize_t show_##value(struct device *dev, char *buf) \ { \ @@ -299,8 +298,6 @@ /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, type_name, I2C_NAME_SIZE); data->type = kind; - - new_client->id = adm1021_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -373,8 +370,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting adm1021 update\n"); data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); diff -Nru a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c --- a/drivers/i2c/chips/adm1025.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/adm1025.c 2005-02-28 17:20:43 -08:00 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -148,12 +149,6 @@ }; /* - * Internal variables - */ - -static int adm1025_id; - -/* * Sysfs stuff */ @@ -397,7 +392,6 @@ /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - new_client->id = adm1025_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -512,9 +506,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || - !data->valid) { + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { int i; dev_dbg(&client->dev, "Updating data.\n"); diff -Nru a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c --- a/drivers/i2c/chips/adm1026.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/adm1026.c 2005-02-28 17:20:43 -08:00 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -313,8 +314,6 @@ .detach_client = adm1026_detach_client, }; -static int adm1026_id; - int adm1026_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) { @@ -363,49 +362,47 @@ int value, i; struct adm1026_data *data = i2c_get_clientdata(client); - dev_dbg(&client->dev,"(%d): Initializing device\n", client->id); + dev_dbg(&client->dev, "Initializing device\n"); /* Read chip config */ data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); /* Inform user of chip config */ - dev_dbg(&client->dev, "(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n", - client->id, data->config1); + dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n", + data->config1); if ((data->config1 & CFG1_MONITOR) == 0) { - dev_dbg(&client->dev, "(%d): Monitoring not currently " - "enabled.\n", client->id); + dev_dbg(&client->dev, "Monitoring not currently " + "enabled.\n"); } if (data->config1 & CFG1_INT_ENABLE) { - dev_dbg(&client->dev, "(%d): SMBALERT interrupts are " - "enabled.\n", client->id); + dev_dbg(&client->dev, "SMBALERT interrupts are " + "enabled.\n"); } if (data->config1 & CFG1_AIN8_9) { - dev_dbg(&client->dev, "(%d): in8 and in9 enabled. " - "temp3 disabled.\n", client->id); + dev_dbg(&client->dev, "in8 and in9 enabled. " + "temp3 disabled.\n"); } else { - dev_dbg(&client->dev, "(%d): temp3 enabled. in8 and " - "in9 disabled.\n", client->id); + dev_dbg(&client->dev, "temp3 enabled. in8 and " + "in9 disabled.\n"); } if (data->config1 & CFG1_THERM_HOT) { - dev_dbg(&client->dev, "(%d): Automatic THERM, PWM, " - "and temp limits enabled.\n", client->id); + dev_dbg(&client->dev, "Automatic THERM, PWM, " + "and temp limits enabled.\n"); } value = data->config3; if (data->config3 & CFG3_GPIO16_ENABLE) { - dev_dbg(&client->dev, "(%d): GPIO16 enabled. THERM" - "pin disabled.\n", client->id); + dev_dbg(&client->dev, "GPIO16 enabled. THERM" + "pin disabled.\n"); } else { - dev_dbg(&client->dev, "(%d): THERM pin enabled. " - "GPIO16 disabled.\n", client->id); + dev_dbg(&client->dev, "THERM pin enabled. " + "GPIO16 disabled.\n"); } if (data->config3 & CFG3_VREF_250) { - dev_dbg(&client->dev, "(%d): Vref is 2.50 Volts.\n", - client->id); + dev_dbg(&client->dev, "Vref is 2.50 Volts.\n"); } else { - dev_dbg(&client->dev, "(%d): Vref is 1.82 Volts.\n", - client->id); + dev_dbg(&client->dev, "Vref is 1.82 Volts.\n"); } /* Read and pick apart the existing GPIO configuration */ value = 0; @@ -423,12 +420,11 @@ adm1026_print_gpio(client); /* If the user asks us to reprogram the GPIO config, then - * do it now. But only if this is the first ADM1026. + * do it now. */ - if (client->id == 0 - && (gpio_input[0] != -1 || gpio_output[0] != -1 + if (gpio_input[0] != -1 || gpio_output[0] != -1 || gpio_inverted[0] != -1 || gpio_normal[0] != -1 - || gpio_fan[0] != -1)) { + || gpio_fan[0] != -1) { adm1026_fixup_gpio(client); } @@ -448,8 +444,7 @@ value = adm1026_read_value(client, ADM1026_REG_CONFIG1); /* Set MONITOR, clear interrupt acknowledge and s/w reset */ value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET); - dev_dbg(&client->dev, "(%d): Setting CONFIG to: 0x%02x\n", - client->id, value); + dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); data->config1 = value; adm1026_write_value(client, ADM1026_REG_CONFIG1, value); @@ -467,31 +462,30 @@ struct adm1026_data *data = i2c_get_clientdata(client); int i; - dev_dbg(&client->dev, "(%d): GPIO config is:", client->id); + dev_dbg(&client->dev, "GPIO config is:"); for (i = 0;i <= 7;++i) { if (data->config2 & (1 << i)) { - dev_dbg(&client->dev, "\t(%d): %sGP%s%d\n", client->id, + dev_dbg(&client->dev, "\t%sGP%s%d\n", data->gpio_config[i] & 0x02 ? "" : "!", data->gpio_config[i] & 0x01 ? "OUT" : "IN", i); } else { - dev_dbg(&client->dev, "\t(%d): FAN%d\n", - client->id, i); + dev_dbg(&client->dev, "\tFAN%d\n", i); } } for (i = 8;i <= 15;++i) { - dev_dbg(&client->dev, "\t(%d): %sGP%s%d\n", client->id, + dev_dbg(&client->dev, "\t%sGP%s%d\n", data->gpio_config[i] & 0x02 ? "" : "!", data->gpio_config[i] & 0x01 ? "OUT" : "IN", i); } if (data->config3 & CFG3_GPIO16_ENABLE) { - dev_dbg(&client->dev, "\t(%d): %sGP%s16\n", client->id, + dev_dbg(&client->dev, "\t%sGP%s16\n", data->gpio_config[16] & 0x02 ? "" : "!", data->gpio_config[16] & 0x01 ? "OUT" : "IN"); } else { /* GPIO16 is THERM */ - dev_dbg(&client->dev, "\t(%d): THERM\n", client->id); + dev_dbg(&client->dev, "\tTHERM\n"); } } @@ -580,10 +574,9 @@ down(&data->update_lock); if (!data->valid - || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL)) { + || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { /* Things that change quickly */ - dev_dbg(&client->dev,"(%d): Reading sensor values\n", - client->id); + dev_dbg(&client->dev,"Reading sensor values\n"); for (i = 0;i <= 16;++i) { data->in[i] = adm1026_read_value(client, ADM1026_REG_IN[i]); @@ -628,11 +621,10 @@ data->last_reading = jiffies; }; /* last_reading */ - if (!data->valid || (jiffies - data->last_config > - ADM1026_CONFIG_INTERVAL)) { + if (!data->valid || + time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { /* Things that don't change often */ - dev_dbg(&client->dev, "(%d): Reading config values\n", - client->id); + dev_dbg(&client->dev, "Reading config values\n"); for (i = 0;i <= 16;++i) { data->in_min[i] = adm1026_read_value(client, ADM1026_REG_IN_MIN[i]); @@ -712,8 +704,7 @@ data->last_config = jiffies; }; /* last_config */ - dev_dbg(&client->dev, "(%d): Setting VID from GPIO11-15.\n", - client->id); + dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); data->vid = (data->gpio >> 11) & 0x1f; data->valid = 1; up(&data->update_lock); @@ -1608,15 +1599,9 @@ strlcpy(new_client->name, type_name, I2C_NAME_SIZE); /* Fill in the remaining client fields */ - new_client->id = adm1026_id++; data->type = kind; data->valid = 0; init_MUTEX(&data->update_lock); - - dev_dbg(&new_client->dev, "(%d): Assigning ID %d to %s at %d,0x%02x\n", - new_client->id, new_client->id, new_client->name, - i2c_adapter_id(new_client->adapter), - new_client->addr); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) diff -Nru a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c --- a/drivers/i2c/chips/adm1031.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/adm1031.c 2005-02-28 17:20:43 -08:00 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -110,8 +111,6 @@ .detach_client = adm1031_detach_client, }; -static int adm1031_id; - static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -781,8 +780,6 @@ data->chip_type = kind; strlcpy(new_client->name, name, I2C_NAME_SIZE); - - new_client->id = adm1031_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -888,8 +885,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting adm1031 update\n"); for (chan = 0; diff -Nru a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c --- a/drivers/i2c/chips/asb100.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/asb100.c 2005-02-28 17:20:43 -08:00 @@ -36,17 +36,12 @@ asb100 7 3 1 4 0x31 0x0694 yes no */ -#include #include #include -#include -#include #include #include #include #include -#include -#include #include "lm75.h" /* @@ -970,8 +965,8 @@ down(&data->update_lock); - if (time_after(jiffies - data->last_updated, (unsigned long)(HZ+HZ/2)) - || time_before(jiffies, data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "starting device update...\n"); diff -Nru a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c --- a/drivers/i2c/chips/ds1621.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/ds1621.c 2005-02-28 17:20:43 -08:00 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "lm75.h" @@ -95,8 +96,6 @@ .detach_client = ds1621_detach_client, }; -static int ds1621_id; - /* All registers are word-sized, except for the configuration register. DS1621 uses a high-byte first convention, which is exactly opposite to the usual practice. */ @@ -236,8 +235,6 @@ /* Fill in remaining client fields and put it into the global list */ strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE); - - new_client->id = ds1621_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -288,8 +285,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting ds1621 update\n"); diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c --- a/drivers/i2c/chips/eeprom.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/eeprom.c 2005-02-28 17:20:43 -08:00 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -86,8 +87,7 @@ down(&data->update_lock); if (!(data->valid & (1 << slice)) || - (jiffies - data->last_updated[slice] > 300 * HZ) || - (jiffies < data->last_updated[slice])) { + time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { diff -Nru a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c --- a/drivers/i2c/chips/fscher.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/fscher.c 2005-02-28 17:20:43 -08:00 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -151,12 +152,6 @@ }; /* - * Internal variables - */ - -static int fscher_id; - -/* * Sysfs stuff */ @@ -337,7 +332,6 @@ /* Fill in the remaining client fields and put it into the * global list */ strlcpy(new_client->name, "fscher", I2C_NAME_SIZE); - new_client->id = fscher_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -418,8 +412,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { dev_dbg(&client->dev, "Starting fscher update\n"); diff -Nru a/drivers/i2c/chips/fscpos.c b/drivers/i2c/chips/fscpos.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/fscpos.c 2005-02-28 17:20:43 -08:00 @@ -0,0 +1,631 @@ +/* + fscpos.c - Kernel module for hardware monitoring with FSC Poseidon chips + Copyright (C) 2004, 2005 Stefan Ott + + 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. +*/ + +/* + fujitsu siemens poseidon chip, + module based on the old fscpos module by Hermann Jung and + the fscher module by Reinhard Nissl + + original module based on lm80.c + Copyright (C) 1998, 1999 Frodo Looijaard + and Philip Edelbrock + + Thanks to Jean Delvare for reviewing my code and suggesting a lot of + improvements. +*/ + +#include +#include +#include +#include +#include + +/* + * Addresses to scan + */ +static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ +SENSORS_INSMOD_1(fscpos); + +/* + * The FSCPOS registers + */ + +/* chip identification */ +#define FSCPOS_REG_IDENT_0 0x00 +#define FSCPOS_REG_IDENT_1 0x01 +#define FSCPOS_REG_IDENT_2 0x02 +#define FSCPOS_REG_REVISION 0x03 + +/* global control and status */ +#define FSCPOS_REG_EVENT_STATE 0x04 +#define FSCPOS_REG_CONTROL 0x05 + +/* watchdog */ +#define FSCPOS_REG_WDOG_PRESET 0x28 +#define FSCPOS_REG_WDOG_STATE 0x23 +#define FSCPOS_REG_WDOG_CONTROL 0x21 + +/* voltages */ +#define FSCPOS_REG_VOLT_12 0x45 +#define FSCPOS_REG_VOLT_5 0x42 +#define FSCPOS_REG_VOLT_BATT 0x48 + +/* fans - the chip does not support minimum speed for fan2 */ +static u8 FSCPOS_REG_PWM[] = { 0x55, 0x65 }; +static u8 FSCPOS_REG_FAN_ACT[] = { 0x0e, 0x6b, 0xab }; +static u8 FSCPOS_REG_FAN_STATE[] = { 0x0d, 0x62, 0xa2 }; +static u8 FSCPOS_REG_FAN_RIPPLE[] = { 0x0f, 0x6f, 0xaf }; + +/* temperatures */ +static u8 FSCPOS_REG_TEMP_ACT[] = { 0x64, 0x32, 0x35 }; +static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 }; + +/* + * Functions declaration + */ +static int fscpos_attach_adapter(struct i2c_adapter *adapter); +static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind); +static int fscpos_detach_client(struct i2c_client *client); + +static int fscpos_read_value(struct i2c_client *client, u8 register); +static int fscpos_write_value(struct i2c_client *client, u8 register, u8 value); +static struct fscpos_data *fscpos_update_device(struct device *dev); +static void fscpos_init_client(struct i2c_client *client); + +static void reset_fan_alarm(struct i2c_client *client, int nr); + +/* + * Driver data (common to all clients) + */ +static struct i2c_driver fscpos_driver = { + .owner = THIS_MODULE, + .name = "fscpos", + .id = I2C_DRIVERID_FSCPOS, + .flags = I2C_DF_NOTIFY, + .attach_adapter = fscpos_attach_adapter, + .detach_client = fscpos_detach_client, +}; + +/* + * Client data (each client gets its own) + */ +struct fscpos_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* 0 until following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* register values */ + u8 revision; /* revision of chip */ + u8 global_event; /* global event status */ + u8 global_control; /* global control register */ + u8 wdog_control; /* watchdog control */ + u8 wdog_state; /* watchdog status */ + u8 wdog_preset; /* watchdog preset */ + u8 volt[3]; /* 12, 5, battery current */ + u8 temp_act[3]; /* temperature */ + u8 temp_status[3]; /* status of sensor */ + u8 fan_act[3]; /* fans revolutions per second */ + u8 fan_status[3]; /* fan status */ + u8 pwm[2]; /* fan min value for rps */ + u8 fan_ripple[3]; /* divider for rps */ +}; + +/* Temperature */ +#define TEMP_FROM_REG(val) (((val) - 128) * 1000) + +static ssize_t show_temp_input(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[nr - 1])); +} + +static ssize_t show_temp_status(struct fscpos_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", data->temp_status[nr - 1] & 0x03); +} + +static ssize_t show_temp_reset(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "1\n"); +} + +static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + if (v != 1) { + dev_err(&client->dev, "temp_reset value %ld not supported. " + "Use 1 to reset the alarm!\n", v); + return -EINVAL; + } + + dev_info(&client->dev, "You used the temp_reset feature which has not " + "been proplerly tested. Please report your " + "experience to the module author.\n"); + + /* Supported value: 2 (clears the status) */ + fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr], 2); + return count; +} + +/* Fans */ +#define RPM_FROM_REG(val) ((val) * 60) + +static ssize_t show_fan_status(struct fscpos_data *data, char *buf, int nr) +{ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + return sprintf(buf, "%u\n", data->fan_status[nr - 1] & 0x04); +} + +static ssize_t show_fan_input(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[nr - 1])); +} + +static ssize_t show_fan_ripple(struct fscpos_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", data->fan_ripple[nr - 1] & 0x03); +} + +static ssize_t set_fan_ripple(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int nr, int reg) +{ + /* supported values: 2, 4, 8 */ + unsigned long v = simple_strtoul(buf, NULL, 10); + + switch (v) { + case 2: v = 1; break; + case 4: v = 2; break; + case 8: v = 3; break; + default: + dev_err(&client->dev, "fan_ripple value %ld not supported. " + "Must be one of 2, 4 or 8!\n", v); + return -EINVAL; + } + + /* bits 2..7 reserved => mask with 0x03 */ + data->fan_ripple[nr - 1] &= ~0x03; + data->fan_ripple[nr - 1] |= v; + + fscpos_write_value(client, reg, data->fan_ripple[nr - 1]); + return count; +} + +static ssize_t show_pwm(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->pwm[nr - 1]); +} + +static ssize_t set_pwm(struct i2c_client *client, struct fscpos_data *data, + const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + + /* Range: 0..255 */ + if (v < 0) v = 0; + if (v > 255) v = 255; + + data->pwm[nr - 1] = v; + fscpos_write_value(client, reg, data->pwm[nr - 1]); + return count; +} + +static void reset_fan_alarm(struct i2c_client *client, int nr) +{ + fscpos_write_value(client, FSCPOS_REG_FAN_STATE[nr], 4); +} + +/* Volts */ +#define VOLT_FROM_REG(val, mult) ((val) * (mult) / 255) + +static ssize_t show_volt_12(struct device *dev, char *buf) +{ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200)); +} + +static ssize_t show_volt_5(struct device *dev, char *buf) +{ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600)); +} + +static ssize_t show_volt_batt(struct device *dev, char *buf) +{ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300)); +} + +/* Watchdog */ +static ssize_t show_wdog_control(struct fscpos_data *data, char *buf) +{ + /* bits 0..3 reserved, bit 6 write only => mask with 0xb0 */ + return sprintf(buf, "%u\n", data->wdog_control & 0xb0); +} + +static ssize_t set_wdog_control(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int reg) +{ + /* bits 0..3 reserved => mask with 0xf0 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; + data->wdog_control &= ~0xf0; + data->wdog_control |= v; + + fscpos_write_value(client, reg, data->wdog_control); + return count; +} + +static ssize_t show_wdog_state(struct fscpos_data *data, char *buf) +{ + /* bits 0, 2..7 reserved => mask with 0x02 */ + return sprintf(buf, "%u\n", data->wdog_state & 0x02); +} + +static ssize_t set_wdog_state(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + + /* Valid values: 2 (clear) */ + if (v != 2) { + dev_err(&client->dev, "wdog_state value %ld not supported. " + "Must be 2 to clear the state!\n", v); + return -EINVAL; + } + + data->wdog_state &= ~v; + + fscpos_write_value(client, reg, v); + return count; +} + +static ssize_t show_wdog_preset(struct fscpos_data *data, char *buf) +{ + return sprintf(buf, "%u\n", data->wdog_preset); +} + +static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int reg) +{ + data->wdog_preset = simple_strtoul(buf, NULL, 10) & 0xff; + + fscpos_write_value(client, reg, data->wdog_preset); + return count; +} + +/* Event */ +static ssize_t show_event(struct device *dev, char *buf) +{ + /* bits 5..7 reserved => mask with 0x1f */ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", data->global_event & 0x9b); +} + +/* + * Sysfs stuff + */ +#define create_getter(kind, sub) \ + static ssize_t sysfs_show_##kind##sub(struct device *dev, char *buf) \ + { \ + struct fscpos_data *data = fscpos_update_device(dev); \ + return show_##kind##sub(data, buf); \ + } + +#define create_getter_n(kind, offset, sub) \ + static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, char\ + *buf) \ + { \ + struct fscpos_data *data = fscpos_update_device(dev); \ + return show_##kind##sub(data, buf, offset); \ + } + +#define create_setter(kind, sub, reg) \ + static ssize_t sysfs_set_##kind##sub (struct device *dev, const char \ + *buf, size_t count) \ + { \ + struct i2c_client *client = to_i2c_client(dev); \ + struct fscpos_data *data = i2c_get_clientdata(client); \ + return set_##kind##sub(client, data, buf, count, reg); \ + } + +#define create_setter_n(kind, offset, sub, reg) \ + static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, \ + const char *buf, size_t count) \ + { \ + struct i2c_client *client = to_i2c_client(dev); \ + struct fscpos_data *data = i2c_get_clientdata(client); \ + return set_##kind##sub(client, data, buf, count, offset, reg);\ + } + +#define create_sysfs_device_ro(kind, sub, offset) \ + static DEVICE_ATTR(kind##offset##sub, S_IRUGO, \ + sysfs_show_##kind##offset##sub, NULL); + +#define create_sysfs_device_rw(kind, sub, offset) \ + static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, \ + sysfs_show_##kind##offset##sub, sysfs_set_##kind##offset##sub); + +#define sysfs_ro_n(kind, sub, offset) \ + create_getter_n(kind, offset, sub); \ + create_sysfs_device_ro(kind, sub, offset); + +#define sysfs_rw_n(kind, sub, offset, reg) \ + create_getter_n(kind, offset, sub); \ + create_setter_n(kind, offset, sub, reg); \ + create_sysfs_device_rw(kind, sub, offset); + +#define sysfs_rw(kind, sub, reg) \ + create_getter(kind, sub); \ + create_setter(kind, sub, reg); \ + create_sysfs_device_rw(kind, sub,); + +#define sysfs_fan_with_min(offset, reg_status, reg_ripple, reg_min) \ + sysfs_fan(offset, reg_status, reg_ripple); \ + sysfs_rw_n(pwm,, offset, reg_min); + +#define sysfs_fan(offset, reg_status, reg_ripple) \ + sysfs_ro_n(fan, _input, offset); \ + sysfs_ro_n(fan, _status, offset); \ + sysfs_rw_n(fan, _ripple, offset, reg_ripple); + +#define sysfs_temp(offset, reg_status) \ + sysfs_ro_n(temp, _input, offset); \ + sysfs_ro_n(temp, _status, offset); \ + sysfs_rw_n(temp, _reset, offset, reg_status); + +#define sysfs_watchdog(reg_wdog_preset, reg_wdog_state, reg_wdog_control) \ + sysfs_rw(wdog, _control, reg_wdog_control); \ + sysfs_rw(wdog, _preset, reg_wdog_preset); \ + sysfs_rw(wdog, _state, reg_wdog_state); + +sysfs_fan_with_min(1, FSCPOS_REG_FAN_STATE[0], FSCPOS_REG_FAN_RIPPLE[0], + FSCPOS_REG_PWM[0]); +sysfs_fan_with_min(2, FSCPOS_REG_FAN_STATE[1], FSCPOS_REG_FAN_RIPPLE[1], + FSCPOS_REG_PWM[1]); +sysfs_fan(3, FSCPOS_REG_FAN_STATE[2], FSCPOS_REG_FAN_RIPPLE[2]); + +sysfs_temp(1, FSCPOS_REG_TEMP_STATE[0]); +sysfs_temp(2, FSCPOS_REG_TEMP_STATE[1]); +sysfs_temp(3, FSCPOS_REG_TEMP_STATE[2]); + +sysfs_watchdog(FSCPOS_REG_WDOG_PRESET, FSCPOS_REG_WDOG_STATE, + FSCPOS_REG_WDOG_CONTROL); + +static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); +static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL); +static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL); +static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL); + +static int fscpos_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, fscpos_detect); +} + +int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct fscpos_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* + * OK. For now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + * But it allows us to access fscpos_{read,write}_value. + */ + + if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct fscpos_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &fscpos_driver; + new_client->flags = 0; + + /* Do the remaining detection unless force or force_fscpos parameter */ + if (kind < 0) { + if ((fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) + != 0x50) /* 'P' */ + || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) + != 0x45) /* 'E' */ + || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) + != 0x47))/* 'G' */ + { + dev_dbg(&new_client->dev, "fscpos detection failed\n"); + goto exit_free; + } + } + + /* Fill in the remaining client fields and put it in the global list */ + strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE); + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Inizialize the fscpos chip */ + fscpos_init_client(new_client); + + /* Announce that the chip was found */ + dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_event); + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_wdog_control); + device_create_file(&new_client->dev, &dev_attr_wdog_preset); + device_create_file(&new_client->dev, &dev_attr_wdog_state); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_status); + device_create_file(&new_client->dev, &dev_attr_temp1_reset); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_status); + device_create_file(&new_client->dev, &dev_attr_temp2_reset); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_status); + device_create_file(&new_client->dev, &dev_attr_temp3_reset); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_status); + device_create_file(&new_client->dev, &dev_attr_fan1_ripple); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_status); + device_create_file(&new_client->dev, &dev_attr_fan2_ripple); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_fan3_input); + device_create_file(&new_client->dev, &dev_attr_fan3_status); + device_create_file(&new_client->dev, &dev_attr_fan3_ripple); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int fscpos_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; +} + +static int fscpos_read_value(struct i2c_client *client, u8 reg) +{ + dev_dbg(&client->dev, "Read reg 0x%02x\n", reg); + return i2c_smbus_read_byte_data(client, reg); +} + +static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + dev_dbg(&client->dev, "Write reg 0x%02x, val 0x%02x\n", reg, value); + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new FSCPOS chip */ +static void fscpos_init_client(struct i2c_client *client) +{ + struct fscpos_data *data = i2c_get_clientdata(client); + + /* read revision from chip */ + data->revision = fscpos_read_value(client, FSCPOS_REG_REVISION); +} + +static struct fscpos_data *fscpos_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fscpos_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting fscpos update\n"); + + for (i = 0; i < 3; i++) { + data->temp_act[i] = fscpos_read_value(client, + FSCPOS_REG_TEMP_ACT[i]); + data->temp_status[i] = fscpos_read_value(client, + FSCPOS_REG_TEMP_STATE[i]); + data->fan_act[i] = fscpos_read_value(client, + FSCPOS_REG_FAN_ACT[i]); + data->fan_status[i] = fscpos_read_value(client, + FSCPOS_REG_FAN_STATE[i]); + data->fan_ripple[i] = fscpos_read_value(client, + FSCPOS_REG_FAN_RIPPLE[i]); + if (i < 2) { + /* fan2_min is not supported by the chip */ + data->pwm[i] = fscpos_read_value(client, + FSCPOS_REG_PWM[i]); + } + /* reset fan status if speed is back to > 0 */ + if (data->fan_status[i] != 0 && data->fan_act[i] > 0) { + reset_fan_alarm(client, i); + } + } + + data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12); + data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5); + data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT); + + data->wdog_preset = fscpos_read_value(client, + FSCPOS_REG_WDOG_PRESET); + data->wdog_state = fscpos_read_value(client, + FSCPOS_REG_WDOG_STATE); + data->wdog_control = fscpos_read_value(client, + FSCPOS_REG_WDOG_CONTROL); + + data->global_event = fscpos_read_value(client, + FSCPOS_REG_EVENT_STATE); + + data->last_updated = jiffies; + data->valid = 1; + } + up(&data->update_lock); + return data; +} + +static int __init sm_fscpos_init(void) +{ + return i2c_add_driver(&fscpos_driver); +} + +static void __exit sm_fscpos_exit(void) +{ + i2c_del_driver(&fscpos_driver); +} + +MODULE_AUTHOR("Stefan Ott based on work from Hermann Jung " + ", Frodo Looijaard " + " and Philip Edelbrock "); +MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_fscpos_init); +module_exit(sm_fscpos_exit); diff -Nru a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c --- a/drivers/i2c/chips/gl518sm.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/gl518sm.c 2005-02-28 17:20:43 -08:00 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -159,12 +160,6 @@ }; /* - * Internal variables - */ - -static int gl518_id; - -/* * Sysfs stuff */ @@ -396,7 +391,6 @@ /* Fill in the remaining client fields */ strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); - new_client->id = gl518_id++; data->type = kind; data->valid = 0; init_MUTEX(&data->update_lock); @@ -512,8 +506,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting gl518 update\n"); data->alarms = gl518_read_value(client, GL518_REG_INT); diff -Nru a/drivers/i2c/chips/gl520sm.c b/drivers/i2c/chips/gl520sm.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/gl520sm.c 2005-02-28 17:20:43 -08:00 @@ -0,0 +1,754 @@ +/* + gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard , + Kyösti Mälkki + Copyright (c) 2005 Maarten Deprez + + 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 +#include +#include +#include +#include +#include + +/* Type of the extra sensor */ +static unsigned short extra_sensor_type; +module_param(extra_sensor_type, ushort, 0); +MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(gl520sm); + +/* Many GL520 constants specified below +One of the inputs can be configured as either temp or voltage. +That's why _TEMP2 and _IN4 access the same register +*/ + +/* The GL520 registers */ +#define GL520_REG_CHIP_ID 0x00 +#define GL520_REG_REVISION 0x01 +#define GL520_REG_CONF 0x03 +#define GL520_REG_MASK 0x11 + +#define GL520_REG_VID_INPUT 0x02 + +#define GL520_REG_IN0_INPUT 0x15 +#define GL520_REG_IN0_LIMIT 0x0c +#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT +#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT + +#define GL520_REG_IN1_INPUT 0x14 +#define GL520_REG_IN1_LIMIT 0x09 +#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT +#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT + +#define GL520_REG_IN2_INPUT 0x13 +#define GL520_REG_IN2_LIMIT 0x0a +#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT +#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT + +#define GL520_REG_IN3_INPUT 0x0d +#define GL520_REG_IN3_LIMIT 0x0b +#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT +#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT + +#define GL520_REG_IN4_INPUT 0x0e +#define GL520_REG_IN4_MAX 0x17 +#define GL520_REG_IN4_MIN 0x18 + +#define GL520_REG_TEMP1_INPUT 0x04 +#define GL520_REG_TEMP1_MAX 0x05 +#define GL520_REG_TEMP1_MAX_HYST 0x06 + +#define GL520_REG_TEMP2_INPUT 0x0e +#define GL520_REG_TEMP2_MAX 0x17 +#define GL520_REG_TEMP2_MAX_HYST 0x18 + +#define GL520_REG_FAN_INPUT 0x07 +#define GL520_REG_FAN_MIN 0x08 +#define GL520_REG_FAN_DIV 0x0f +#define GL520_REG_FAN_OFF GL520_REG_FAN_DIV + +#define GL520_REG_ALARMS 0x12 +#define GL520_REG_BEEP_MASK 0x10 +#define GL520_REG_BEEP_ENABLE GL520_REG_CONF + +/* + * Function declarations + */ + +static int gl520_attach_adapter(struct i2c_adapter *adapter); +static int gl520_detect(struct i2c_adapter *adapter, int address, int kind); +static void gl520_init_client(struct i2c_client *client); +static int gl520_detach_client(struct i2c_client *client); +static int gl520_read_value(struct i2c_client *client, u8 reg); +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct gl520_data *gl520_update_device(struct device *dev); + +/* Driver data */ +static struct i2c_driver gl520_driver = { + .owner = THIS_MODULE, + .name = "gl520sm", + .id = I2C_DRIVERID_GL520, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl520_attach_adapter, + .detach_client = gl520_detach_client, +}; + +/* Client data */ +struct gl520_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until the following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + u8 vid; + u8 vrm; + u8 in_input[5]; /* [0] = VVD */ + u8 in_min[5]; /* [0] = VDD */ + u8 in_max[5]; /* [0] = VDD */ + u8 fan_input[2]; + u8 fan_min[2]; + u8 fan_div[2]; + u8 fan_off; + u8 temp_input[2]; + u8 temp_max[2]; + u8 temp_max_hyst[2]; + u8 alarms; + u8 beep_enable; + u8 beep_mask; + u8 alarm_mask; + u8 two_temps; +}; + +/* + * Sysfs stuff + */ + +#define sysfs_r(type, n, item, reg) \ +static ssize_t get_##type##item (struct gl520_data *, char *, int); \ +static ssize_t get_##type##n##item (struct device *, char *); \ +static ssize_t get_##type##n##item (struct device *dev, char *buf) \ +{ \ + struct gl520_data *data = gl520_update_device(dev); \ + return get_##type##item(data, buf, (n)); \ +} + +#define sysfs_w(type, n, item, reg) \ +static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ +static ssize_t set_##type##n##item (struct device *, const char *, size_t); \ +static ssize_t set_##type##n##item (struct device *dev, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl520_data *data = i2c_get_clientdata(client); \ + return set_##type##item(client, data, buf, count, (n), reg); \ +} + +#define sysfs_rw_n(type, n, item, reg) \ +sysfs_r(type, n, item, reg) \ +sysfs_w(type, n, item, reg) \ +static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); + +#define sysfs_ro_n(type, n, item, reg) \ +sysfs_r(type, n, item, reg) \ +static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); + +#define sysfs_rw(type, item, reg) \ +sysfs_r(type, 0, item, reg) \ +sysfs_w(type, 0, item, reg) \ +static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); + +#define sysfs_ro(type, item, reg) \ +sysfs_r(type, 0, item, reg) \ +static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); + + +#define sysfs_vid(n) \ +sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) + +#define device_create_file_vid(client, n) \ +device_create_file(&client->dev, &dev_attr_cpu##n##_vid) + +#define sysfs_in(n) \ +sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ +sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ +sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ + +#define device_create_file_in(client, n) \ +({device_create_file(&client->dev, &dev_attr_in##n##_input); \ +device_create_file(&client->dev, &dev_attr_in##n##_min); \ +device_create_file(&client->dev, &dev_attr_in##n##_max);}) + +#define sysfs_fan(n) \ +sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ +sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ +sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) + +#define device_create_file_fan(client, n) \ +({device_create_file(&client->dev, &dev_attr_fan##n##_input); \ +device_create_file(&client->dev, &dev_attr_fan##n##_min); \ +device_create_file(&client->dev, &dev_attr_fan##n##_div);}) + +#define sysfs_fan_off(n) \ +sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ + +#define device_create_file_fan_off(client, n) \ +device_create_file(&client->dev, &dev_attr_fan##n##_off) + +#define sysfs_temp(n) \ +sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ +sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ +sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) + +#define device_create_file_temp(client, n) \ +({device_create_file(&client->dev, &dev_attr_temp##n##_input); \ +device_create_file(&client->dev, &dev_attr_temp##n##_max); \ +device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);}) + +#define sysfs_alarms() \ +sysfs_ro(alarms, , GL520_REG_ALARMS) \ +sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ +sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) + +#define device_create_file_alarms(client) \ +({device_create_file(&client->dev, &dev_attr_alarms); \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask);}) + + +sysfs_vid(0) + +sysfs_in(0) +sysfs_in(1) +sysfs_in(2) +sysfs_in(3) +sysfs_in(4) + +sysfs_fan(1) +sysfs_fan(2) +sysfs_fan_off(1) + +sysfs_temp(1) +sysfs_temp(2) + +sysfs_alarms() + + +static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} + +#define VDD_FROM_REG(val) (((val)*95+2)/4) +#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) + +#define IN_FROM_REG(val) ((val)*19) +#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) + +static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_input[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_min[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_max[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r; + + if (n == 0) + r = VDD_TO_REG(v); + else + r = IN_TO_REG(v); + + data->in_min[n] = r; + + if (n < 4) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + else + gl520_write_value(client, reg, r); + + return count; +} + +static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r; + + if (n == 0) + r = VDD_TO_REG(v); + else + r = IN_TO_REG(v); + + data->in_max[n] = r; + + if (n < 4) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + else + gl520_write_value(client, reg, r); + + return count; +} + +#define DIV_FROM_REG(val) (1 << (val)) +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) +#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); + +static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); +} + +static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); +} + +static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); +} + +static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->fan_off); +} + +static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r = FAN_TO_REG(v, data->fan_div[n - 1]); + + data->fan_min[n - 1] = r; + + if (n == 1) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + if (data->fan_min[n - 1] == 0) + data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; + else + data->alarm_mask |= (n == 1) ? 0x20 : 0x40; + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); + + return count; +} + +static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r; + + switch (v) { + case 1: r = 0; break; + case 2: r = 1; break; + case 4: r = 2; break; + case 8: r = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); + return -EINVAL; + } + + data->fan_div[n - 1] = r; + + if (n == 1) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); + + return count; +} + +static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10)?1:0; + + data->fan_off = r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); + + return count; +} + +#define TEMP_FROM_REG(val) (((val) - 130) * 1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) + +static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); +} + +static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); +} + +static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); +} + +static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r = TEMP_TO_REG(v); + + data->temp_max[n - 1] = r; + gl520_write_value(client, reg, r); + + return count; +} + +static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r = TEMP_TO_REG(v); + + data->temp_max_hyst[n - 1] = r; + gl520_write_value(client, reg, r); + + return count; +} + +static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->beep_enable); +} + +static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->beep_mask); +} + +static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10)?0:1; + + data->beep_enable = !r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); + + return count; +} + +static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10) & data->alarm_mask; + + data->beep_mask = r; + gl520_write_value(client, reg, r); + + return count; +} + + +/* + * Real code + */ + +static int gl520_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, gl520_detect); +} + +static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct gl520_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access gl520_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct gl520_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &gl520_driver; + new_client->flags = 0; + + /* Determine the chip type. */ + if (kind < 0) { + if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || + ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || + ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { + dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); + goto exit_free; + } + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the GL520SM chip */ + gl520_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file_vid(new_client, 0); + + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + if (!data->two_temps) + device_create_file_in(new_client, 4); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan_off(new_client, 1); + + device_create_file_temp(new_client, 1); + if (data->two_temps) + device_create_file_temp(new_client, 2); + + device_create_file_alarms(new_client); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + + +/* Called when we have found a new GL520SM. */ +static void gl520_init_client(struct i2c_client *client) +{ + struct gl520_data *data = i2c_get_clientdata(client); + u8 oldconf, conf; + + conf = oldconf = gl520_read_value(client, GL520_REG_CONF); + + data->alarm_mask = 0xff; + data->vrm = i2c_which_vrm(); + + if (extra_sensor_type == 1) + conf &= ~0x10; + else if (extra_sensor_type == 2) + conf |= 0x10; + data->two_temps = !(conf & 0x10); + + /* If IRQ# is disabled, we can safely force comparator mode */ + if (!(conf & 0x20)) + conf &= 0xf7; + + /* Enable monitoring if needed */ + conf |= 0x40; + + if (conf != oldconf) + gl520_write_value(client, GL520_REG_CONF, conf); + + gl520_update_device(&(client->dev)); + + if (data->fan_min[0] == 0) + data->alarm_mask &= ~0x20; + if (data->fan_min[1] == 0) + data->alarm_mask &= ~0x40; + + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); +} + +static int gl520_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; +} + + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL520 uses a high-byte first convention */ +static int gl520_read_value(struct i2c_client *client, u8 reg) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return swab16(i2c_smbus_read_word_data(client, reg)); + else + return i2c_smbus_read_byte_data(client, reg); +} + +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_write_word_data(client, reg, swab16(value)); + else + return i2c_smbus_write_byte_data(client, reg, value); +} + + +static struct gl520_data *gl520_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int val; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { + + dev_dbg(&client->dev, "Starting gl520sm update\n"); + + data->alarms = gl520_read_value(client, GL520_REG_ALARMS); + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; + + val = gl520_read_value(client, GL520_REG_IN0_LIMIT); + data->in_min[0] = val & 0xff; + data->in_max[0] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN1_LIMIT); + data->in_min[1] = val & 0xff; + data->in_max[1] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN2_LIMIT); + data->in_min[2] = val & 0xff; + data->in_max[2] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN3_LIMIT); + data->in_min[3] = val & 0xff; + data->in_max[3] = (val >> 8) & 0xff; + + val = gl520_read_value(client, GL520_REG_FAN_INPUT); + data->fan_input[0] = (val >> 8) & 0xff; + data->fan_input[1] = val & 0xff; + + val = gl520_read_value(client, GL520_REG_FAN_MIN); + data->fan_min[0] = (val >> 8) & 0xff; + data->fan_min[1] = val & 0xff; + + data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); + data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); + data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); + + val = gl520_read_value(client, GL520_REG_FAN_DIV); + data->fan_div[0] = (val >> 6) & 0x03; + data->fan_div[1] = (val >> 4) & 0x03; + data->fan_off = (val >> 2) & 0x01; + + data->alarms &= data->alarm_mask; + + val = gl520_read_value(client, GL520_REG_CONF); + data->beep_enable = !((val >> 2) & 1); + + data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); + data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); + data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); + data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); + + /* Temp1 and Vin4 are the same input */ + if (data->two_temps) { + data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); + data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); + data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); + } else { + data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); + data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); + data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + + +static int __init sensors_gl520sm_init(void) +{ + return i2c_add_driver(&gl520_driver); +} + +static void __exit sensors_gl520sm_exit(void) +{ + i2c_del_driver(&gl520_driver); +} + + +MODULE_AUTHOR("Frodo Looijaard , " + "Kyösti Mälkki , " + "Maarten Deprez "); +MODULE_DESCRIPTION("GL520SM driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_gl520sm_init); +module_exit(sensors_gl520sm_exit); diff -Nru a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c --- a/drivers/i2c/chips/isp1301_omap.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/isp1301_omap.c 2005-02-28 17:20:43 -08:00 @@ -1503,7 +1503,6 @@ isp->client.addr = address; i2c_set_clientdata(&isp->client, isp); isp->client.adapter = bus; - isp->client.id = 1301; isp->client.driver = &isp1301_driver; strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE); i2c = &isp->client; diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c --- a/drivers/i2c/chips/it87.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/it87.c 2005-02-28 17:20:43 -08:00 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,9 @@ /* Update battery voltage after every reading if true */ static int update_vbat; +/* Not all BIOSes properly configure the PWM registers */ +static int fix_pwm_polarity; + /* Chip Type */ static u16 chip_type; @@ -224,6 +228,7 @@ static int it87_write_value(struct i2c_client *client, u8 register, u8 value); static struct it87_data *it87_update_device(struct device *dev); +static int it87_check_pwm(struct i2c_client *client); static void it87_init_client(struct i2c_client *client, struct it87_data *data); @@ -718,7 +723,6 @@ const char *name = ""; int is_isa = i2c_is_isa_adapter(adapter); int enable_pwm_interface; - int tmp; if (!is_isa && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -822,20 +826,12 @@ if ((err = i2c_attach_client(new_client))) goto ERROR2; + /* Check PWM configuration */ + enable_pwm_interface = it87_check_pwm(new_client); + /* Initialize the IT87 chip */ it87_init_client(new_client, data); - /* Some BIOSes fail to correctly configure the IT87 fans. All fans off - * and polarity set to active low is sign that this is the case so we - * disable pwm control to protect the user. */ - enable_pwm_interface = 1; - tmp = it87_read_value(new_client, IT87_REG_FAN_CTL); - if ((tmp & 0x87) == 0) { - enable_pwm_interface = 0; - dev_info(&new_client->dev, - "detected broken BIOS defaults, disabling pwm interface"); - } - /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in1_input); @@ -966,6 +962,56 @@ return i2c_smbus_write_byte_data(client, reg, value); } +/* Return 1 if and only if the PWM interface is safe to use */ +static int it87_check_pwm(struct i2c_client *client) +{ + /* Some BIOSes fail to correctly configure the IT87 fans. All fans off + * and polarity set to active low is sign that this is the case so we + * disable pwm control to protect the user. */ + int tmp = it87_read_value(client, IT87_REG_FAN_CTL); + if ((tmp & 0x87) == 0) { + if (fix_pwm_polarity) { + /* The user asks us to attempt a chip reconfiguration. + * This means switching to active high polarity and + * inverting all fan speed values. */ + int i; + u8 pwm[3]; + + for (i = 0; i < 3; i++) + pwm[i] = it87_read_value(client, + IT87_REG_PWM(i)); + + /* If any fan is in automatic pwm mode, the polarity + * might be correct, as suspicious as it seems, so we + * better don't change anything (but still disable the + * PWM interface). */ + if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { + dev_info(&client->dev, "Reconfiguring PWM to " + "active high polarity\n"); + it87_write_value(client, IT87_REG_FAN_CTL, + tmp | 0x87); + for (i = 0; i < 3; i++) + it87_write_value(client, + IT87_REG_PWM(i), + 0x7f & ~pwm[i]); + return 1; + } + + dev_info(&client->dev, "PWM configuration is " + "too broken to be fixed\n"); + } + + dev_info(&client->dev, "Detected broken BIOS " + "defaults, disabling PWM interface\n"); + return 0; + } else if (fix_pwm_polarity) { + dev_info(&client->dev, "PWM configuration looks " + "sane, won't touch\n"); + } + + return 1; +} + /* Called when we have found a new IT87. */ static void it87_init_client(struct i2c_client *client, struct it87_data *data) { @@ -1038,8 +1084,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { if (update_vbat) { /* Cleared after each update, so reenable. Value @@ -1126,6 +1172,8 @@ MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); +module_param(fix_pwm_polarity, bool, 0); +MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)"); MODULE_LICENSE("GPL"); module_init(sm_it87_init); diff -Nru a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c --- a/drivers/i2c/chips/lm63.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm63.c 2005-02-28 17:20:43 -08:00 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -492,9 +493,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (data->config & 0x04) { /* tachometer enabled */ /* order matters for fan1_input */ data->fan1_input = i2c_smbus_read_byte_data(client, diff -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c --- a/drivers/i2c/chips/lm75.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm75.c 2005-02-28 17:20:43 -08:00 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include "lm75.h" @@ -73,8 +74,6 @@ .detach_client = lm75_detach_client, }; -static int lm75_id; - #define show(value) \ static ssize_t show_##value(struct device *dev, char *buf) \ { \ @@ -196,8 +195,6 @@ /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - - new_client->id = lm75_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -263,8 +260,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting lm75 update\n"); data->temp_input = lm75_read_value(client, LM75_REG_TEMP); diff -Nru a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c --- a/drivers/i2c/chips/lm77.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm77.c 2005-02-28 17:20:43 -08:00 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -81,8 +82,6 @@ .detach_client = lm77_detach_client, }; -static int lm77_id; - /* straight from the datasheet */ #define LM77_TEMP_MIN (-55000) #define LM77_TEMP_MAX 125000 @@ -295,8 +294,6 @@ /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - - new_client->id = lm77_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -364,8 +361,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting lm77 update\n"); data->temp_input = LM77_TEMP_FROM_REG(lm77_read_value(client, diff -Nru a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c --- a/drivers/i2c/chips/lm78.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm78.c 2005-02-28 17:20:43 -08:00 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -81,9 +82,8 @@ static inline u8 FAN_TO_REG(long rpm, int div) { - if (rpm == 0) + if (rpm <= 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } @@ -94,15 +94,15 @@ /* TEMP: mC (-128C to +127C) REG: 1C/bit, two's complement */ -static inline u8 TEMP_TO_REG(int val) +static inline s8 TEMP_TO_REG(int val) { int nval = SENSORS_LIMIT(val, -128000, 127000) ; - return nval<0 ? (nval-500)/1000+0x100 : (nval+500)/1000; + return nval<0 ? (nval-500)/1000 : (nval+500)/1000; } -static inline int TEMP_FROM_REG(u8 val) +static inline int TEMP_FROM_REG(s8 val) { - return (val>=0x80 ? val-0x100 : val) * 1000; + return val * 1000; } /* VID: mV @@ -112,16 +112,6 @@ return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; } -/* ALARMS: chip-specific bitmask - REG: (same) */ -#define ALARMS_FROM_REG(val) (val) - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static inline u8 DIV_TO_REG(int val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} #define DIV_FROM_REG(val) (1 << (val)) /* There are some complications in a module like this. First off, LM78 chips @@ -157,9 +147,9 @@ u8 in_min[7]; /* Register value */ u8 fan[3]; /* Register value */ u8 fan_min[3]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ + s8 temp; /* Register value */ + s8 temp_over; /* Register value */ + s8 temp_hyst; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u16 alarms; /* Register encoding, combined */ @@ -357,7 +347,17 @@ DIV_FROM_REG(data->fan_div[nr])); unsigned long val = simple_strtoul(buf, NULL, 10); int reg = lm78_read_value(client, LM78_REG_VID_FANDIV); - data->fan_div[nr] = DIV_TO_REG(val); + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + return -EINVAL; + } + switch (nr) { case 0: reg = (reg & 0xcf) | (data->fan_div[nr] << 4); @@ -430,7 +430,7 @@ static ssize_t show_alarms(struct device *dev, char *buf) { struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); @@ -633,17 +633,15 @@ { int err; - /* release ISA region first */ - if(i2c_is_isa_client(client)) - release_region(client->addr, LM78_EXTENT); - - /* now it's safe to scrap the rest */ if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); return err; } + if(i2c_is_isa_client(client)) + release_region(client->addr, LM78_EXTENT); + kfree(i2c_get_clientdata(client)); return 0; @@ -653,9 +651,7 @@ We don't want to lock the whole ISA bus, so we lock each client separately. We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ + would slow down the LM78 access and should not be necessary. */ static int lm78_read_value(struct i2c_client *client, u8 reg) { int res; @@ -709,8 +705,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(&client->dev, "Starting lm78 update\n"); diff -Nru a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c --- a/drivers/i2c/chips/lm80.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm80.c 2005-02-28 17:20:43 -08:00 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -99,10 +100,7 @@ #define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val)<0?\ ((val)-500)/1000:((val)+500)/1000,0,255) -#define ALARMS_FROM_REG(val) (val) - #define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) /* * Client data (each client gets its own) @@ -141,12 +139,6 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); /* - * Internal variables - */ - -static int lm80_id; - -/* * Driver data (common to all clients) */ @@ -269,7 +261,17 @@ DIV_FROM_REG(data->fan_div[nr])); val = simple_strtoul(buf, NULL, 10); - data->fan_div[nr] = DIV_TO_REG(val); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + return -EINVAL; + } reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1))); @@ -327,7 +329,7 @@ static ssize_t show_alarms(struct device *dev, char *buf) { struct lm80_data *data = lm80_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0); @@ -425,8 +427,6 @@ /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - - new_client->id = lm80_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -530,9 +530,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { dev_dbg(&client->dev, "Starting lm80 update\n"); for (i = 0; i <= 6; i++) { data->in[i] = diff -Nru a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c --- a/drivers/i2c/chips/lm83.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm83.c 2005-02-28 17:20:43 -08:00 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -150,12 +151,6 @@ }; /* - * Internal variables - */ - -static int lm83_id; - -/* * Sysfs stuff */ @@ -312,7 +307,6 @@ /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - new_client->id = lm83_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -369,9 +363,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || - !data->valid) { + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { int nr; dev_dbg(&client->dev, "Updating lm83 data.\n"); diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c --- a/drivers/i2c/chips/lm85.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm85.c 2005-02-28 17:20:43 -08:00 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -389,9 +390,6 @@ .detach_client = lm85_detach_client, }; -/* Unique ID assigned to each LM85 detected */ -static int lm85_id; - /* 4 Fans */ static ssize_t show_fan(struct device *dev, char *buf, int nr) @@ -1148,16 +1146,10 @@ strlcpy(new_client->name, type_name, I2C_NAME_SIZE); /* Fill in the remaining client fields */ - new_client->id = lm85_id++; data->type = kind; data->valid = 0; init_MUTEX(&data->update_lock); - dev_dbg(&adapter->dev, "Assigning ID %d to %s at %d,0x%02x\n", - new_client->id, new_client->name, - i2c_adapter_id(new_client->adapter), - new_client->addr); - /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto ERROR1; @@ -1363,7 +1355,7 @@ down(&data->update_lock); if ( !data->valid || - (jiffies - data->last_reading > LM85_DATA_INTERVAL ) ) { + time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { /* Things that change quickly */ dev_dbg(&client->dev, "Reading sensor values\n"); @@ -1417,7 +1409,7 @@ }; /* last_reading */ if ( !data->valid || - (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) { + time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) { /* Things that don't change often */ dev_dbg(&client->dev, "Reading config values\n"); diff -Nru a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c --- a/drivers/i2c/chips/lm87.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm87.c 2005-02-28 17:20:43 -08:00 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -203,12 +204,6 @@ }; /* - * Internal variables - */ - -static int lm87_id; - -/* * Sysfs stuff */ @@ -569,7 +564,6 @@ /* We can fill in the remaining client fields */ strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); - new_client->id = lm87_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -720,9 +714,7 @@ down(&data->update_lock); - if (jiffies - data->last_updated > HZ - || jiffies < data->last_updated - || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { int i, j; dev_dbg(&client->dev, "Updating data.\n"); diff -Nru a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c --- a/drivers/i2c/chips/lm90.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/lm90.c 2005-02-28 17:20:43 -08:00 @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -190,12 +191,6 @@ }; /* - * Internal variables - */ - -static int lm90_id; - -/* * Sysfs stuff */ @@ -427,7 +422,6 @@ /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - new_client->id = lm90_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -495,9 +489,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || - !data->valid) { + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { u8 oldh, newh; dev_dbg(&client->dev, "Updating lm90 data.\n"); diff -Nru a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/m41t00.c 2005-02-28 17:20:43 -08:00 @@ -0,0 +1,247 @@ +/* + * drivers/i2c/chips/m41t00.c + * + * I2C client/driver for the ST M41T00 Real-Time Clock chip. + * + * Author: Mark A. Greer + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +/* + * This i2c client/driver wedges between the drivers/char/genrtc.c RTC + * interface and the SMBus interface of the i2c subsystem. + * It would be more efficient to use i2c msgs/i2c_transfer directly but, as + * recommened in .../Documentation/i2c/writing-clients section + * "Sending and receiving", using SMBus level communication is preferred. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define M41T00_DRV_NAME "m41t00" + +static DECLARE_MUTEX(m41t00_mutex); + +static struct i2c_driver m41t00_driver; +static struct i2c_client *save_client; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .normal_i2c_range = ignore, + .probe = ignore, + .probe_range = ignore, + .ignore = ignore, + .ignore_range = ignore, + .force = ignore, +}; + +ulong +m41t00_get_rtc_time(void) +{ + s32 sec, min, hour, day, mon, year; + s32 sec1, min1, hour1, day1, mon1, year1; + ulong limit = 10; + + sec = min = hour = day = mon = year = 0; + sec1 = min1 = hour1 = day1 = mon1 = year1 = 0; + + down(&m41t00_mutex); + do { + if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0) + && ((min = i2c_smbus_read_byte_data(save_client, 1)) + >= 0) + && ((hour = i2c_smbus_read_byte_data(save_client, 2)) + >= 0) + && ((day = i2c_smbus_read_byte_data(save_client, 4)) + >= 0) + && ((mon = i2c_smbus_read_byte_data(save_client, 5)) + >= 0) + && ((year = i2c_smbus_read_byte_data(save_client, 6)) + >= 0) + && ((sec == sec1) && (min == min1) && (hour == hour1) + && (day == day1) && (mon == mon1) + && (year == year1))) + + break; + + sec1 = sec; + min1 = min; + hour1 = hour; + day1 = day; + mon1 = mon; + year1 = year; + } while (--limit > 0); + up(&m41t00_mutex); + + if (limit == 0) { + dev_warn(&save_client->dev, + "m41t00: can't read rtc chip\n"); + sec = min = hour = day = mon = year = 0; + } + + sec &= 0x7f; + min &= 0x7f; + hour &= 0x3f; + day &= 0x3f; + mon &= 0x1f; + year &= 0xff; + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + year += 1900; + if (year < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +static void +m41t00_set_tlet(ulong arg) +{ + struct rtc_time tm; + ulong nowtime = *(ulong *)arg; + + to_tm(nowtime, &tm); + tm.tm_year = (tm.tm_year - 1900) % 100; + + BIN_TO_BCD(tm.tm_sec); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_mon); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + + down(&m41t00_mutex); + if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0) + || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f) + < 0) + || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x7f) + < 0) + || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x7f) + < 0) + || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x7f) + < 0) + || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0x7f) + < 0)) + + dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n"); + + up(&m41t00_mutex); + return; +} + +ulong new_time; + +DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time); + +int +m41t00_set_rtc_time(ulong nowtime) +{ + new_time = nowtime; + + if (in_interrupt()) + tasklet_schedule(&m41t00_tasklet); + else + m41t00_set_tlet((ulong)&new_time); + + return 0; +} + +/* + ***************************************************************************** + * + * Driver Interface + * + ***************************************************************************** + */ +static int +m41t00_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct i2c_client *client; + int rc; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + 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; + client->driver = &m41t00_driver; + + if ((rc = i2c_attach_client(client)) != 0) { + kfree(client); + return rc; + } + + save_client = client; + return 0; +} + +static int +m41t00_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, m41t00_probe); +} + +static int +m41t00_detach(struct i2c_client *client) +{ + int rc; + + if ((rc = i2c_detach_client(client)) == 0) { + kfree(i2c_get_clientdata(client)); + tasklet_kill(&m41t00_tasklet); + } + return rc; +} + +static struct i2c_driver m41t00_driver = { + .owner = THIS_MODULE, + .name = M41T00_DRV_NAME, + .id = I2C_DRIVERID_STM41T00, + .flags = I2C_DF_NOTIFY, + .attach_adapter = m41t00_attach, + .detach_client = m41t00_detach, +}; + +static int __init +m41t00_init(void) +{ + return i2c_add_driver(&m41t00_driver); +} + +static void __exit +m41t00_exit(void) +{ + i2c_del_driver(&m41t00_driver); + return; +} + +module_init(m41t00_init); +module_exit(m41t00_exit); + +MODULE_AUTHOR("Mark A. Greer "); +MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c --- a/drivers/i2c/chips/max1619.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/max1619.c 2005-02-28 17:20:43 -08:00 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -117,12 +118,6 @@ }; /* - * Internal variables - */ - -static int max1619_id; - -/* * Sysfs stuff */ @@ -267,7 +262,6 @@ /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); - new_client->id = max1619_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -331,10 +325,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || - !data->valid) { - + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { dev_dbg(&client->dev, "Updating max1619 data.\n"); data->temp_input1 = i2c_smbus_read_byte_data(client, MAX1619_REG_R_LOCAL_TEMP); diff -Nru a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c --- a/drivers/i2c/chips/pc87360.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/pc87360.c 2005-02-28 17:20:43 -08:00 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1174,8 +1175,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ * 2) - || (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { dev_dbg(&client->dev, "Data update\n"); /* Fans */ diff -Nru a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c --- a/drivers/i2c/chips/pcf8574.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/pcf8574.c 2005-02-28 17:20:43 -08:00 @@ -77,8 +77,6 @@ .detach_client = pcf8574_detach_client, }; -static int pcf8574_id; - /* following are the sysfs callback functions */ static ssize_t show_read(struct device *dev, char *buf) { @@ -159,8 +157,6 @@ /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - - new_client->id = pcf8574_id++; init_MUTEX(&data->update_lock); /* Tell the I2C layer a new client has arrived */ diff -Nru a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c --- a/drivers/i2c/chips/pcf8591.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/pcf8591.c 2005-02-28 17:20:43 -08:00 @@ -98,8 +98,6 @@ .detach_client = pcf8591_detach_client, }; -static int pcf8591_id; - /* following are the sysfs callback functions */ #define show_in_channel(channel) \ static ssize_t show_in##channel##_input(struct device *dev, char *buf) \ @@ -201,8 +199,6 @@ /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE); - - new_client->id = pcf8591_id++; init_MUTEX(&data->update_lock); /* Tell the I2C layer a new client has arrived */ diff -Nru a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c --- a/drivers/i2c/chips/rtc8564.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/rtc8564.c 2005-02-28 17:20:43 -08:00 @@ -89,7 +89,7 @@ _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len); - if (!buf || !client) { + if (!buf) { ret = -EINVAL; goto done; } @@ -111,7 +111,7 @@ struct i2c_msg wr; int i; - if (!client || !data || len > 15) { + if (!data || len > 15) { ret = -EINVAL; goto done; } @@ -163,14 +163,12 @@ strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); i2c_set_clientdata(new_client, d); - new_client->id = rtc8564_driver.id; new_client->flags = I2C_CLIENT_ALLOW_USE | I2C_DF_NOTIFY; new_client->addr = addr; new_client->adapter = adap; new_client->driver = &rtc8564_driver; _DBG(1, "client=%p", new_client); - _DBG(1, "client.id=%d", new_client->id); /* init ctrl1 reg */ data[0] = 0; @@ -222,7 +220,7 @@ _DBG(1, "client=%p, dt=%p", client, dt); - if (!dt || !client) + if (!dt) return -EINVAL; memset(buf, 0, sizeof(buf)); @@ -256,7 +254,7 @@ _DBG(1, "client=%p, dt=%p", client, dt); - if (!dt || !client) + if (!dt) return -EINVAL; _DBGRTCTM(2, *dt); @@ -295,7 +293,7 @@ { struct rtc8564_data *data = i2c_get_clientdata(client); - if (!ctrl || !client) + if (!ctrl) return -1; *ctrl = data->ctrl; @@ -307,7 +305,7 @@ struct rtc8564_data *data = i2c_get_clientdata(client); unsigned char buf[2]; - if (!ctrl || !client) + if (!ctrl) return -1; buf[0] = *ctrl & 0xff; @@ -320,7 +318,7 @@ static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem) { - if (!mem || !client) + if (!mem) return -EINVAL; return rtc8564_read(client, mem->loc, mem->data, mem->nr); @@ -329,7 +327,7 @@ static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem) { - if (!mem || !client) + if (!mem) return -EINVAL; return rtc8564_write(client, mem->loc, mem->data, mem->nr); diff -Nru a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/sis5595.c 2005-02-28 17:20:43 -08:00 @@ -0,0 +1,794 @@ +/* + sis5595.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Copyright (C) 1998 - 2001 Frodo Looijaard , + Kyösti Mälkki , and + Mark D. Studebaker + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + 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. +*/ + +/* + SiS southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c + + Supports following revisions: + Version PCI ID PCI Revision + 1 1039/0008 AF or less + 2 1039/0008 B0 or greater + + 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 + 730 0008 0730 + 735 0008 0735 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* If force_addr is set to anything different from 0, we forcibly enable + the device at the given address. */ +static u16 force_addr; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); + +/* Addresses to scan. + Note that we can't determine the ISA address until we have initialized + our module */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(sis5595); + +/* Many SIS5595 constants specified below */ + +/* Length of ISA address segment */ +#define SIS5595_EXTENT 8 +/* PCI Config Registers */ +#define SIS5595_REVISION_REG 0x08 +#define SIS5595_BASE_REG 0x68 +#define SIS5595_PIN_REG 0x7A +#define SIS5595_ENABLE_REG 0x7B + +/* Where are the ISA address/data registers relative to the base address */ +#define SIS5595_ADDR_REG_OFFSET 5 +#define SIS5595_DATA_REG_OFFSET 6 + +/* The SIS5595 registers */ +#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define SIS5595_REG_IN(nr) (0x20 + (nr)) + +#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) +#define SIS5595_REG_FAN(nr) (0x28 + (nr)) + +/* On the first version of the chip, the temp registers are separate. + On the second version, + TEMP pin is shared with IN4, configured in PCI register 0x7A. + The registers are the same as well. + OVER and HYST are really MAX and MIN. */ + +#define REV2MIN 0xb0 +#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN(4) : 0x27 +#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MAX(4) : 0x39 +#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MIN(4) : 0x3a + +#define SIS5595_REG_CONFIG 0x40 +#define SIS5595_REG_ALARM1 0x41 +#define SIS5595_REG_ALARM2 0x42 +#define SIS5595_REG_FANDIV 0x47 + +/* Conversions. Limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm <= 0) + return 255; + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-54.12C to +157.53C) + REG: 0.83C/bit + 52.12, two's complement */ +static inline int TEMP_FROM_REG(s8 val) +{ + return val * 830 + 52120; +} +static inline s8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -54120, 157530) ; + return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830; +} + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static inline u8 DIV_TO_REG(int val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} +#define DIV_FROM_REG(val) (1 << (val)) + +/* For the SIS5595, we need to keep some data in memory. That + data is pointed to by sis5595_list[NR]->data. The structure itself is + dynamically allocated, at the time when the new sis5595 client is + allocated. */ +struct sis5595_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + char maxins; /* == 3 if temp enabled, otherwise == 4 */ + u8 revision; /* Reg. value */ + + u8 in[5]; /* Register value */ + u8 in_max[5]; /* Register value */ + u8 in_min[5]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + s8 temp; /* Register value */ + s8 temp_over; /* Register value */ + s8 temp_hyst; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 alarms; /* Register encoding, combined */ +}; + +static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ + +static int sis5595_attach_adapter(struct i2c_adapter *adapter); +static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind); +static int sis5595_detach_client(struct i2c_client *client); + +static int sis5595_read_value(struct i2c_client *client, u8 register); +static int sis5595_write_value(struct i2c_client *client, u8 register, u8 value); +static struct sis5595_data *sis5595_update_device(struct device *dev); +static void sis5595_init_client(struct i2c_client *client); + +static struct i2c_driver sis5595_driver = { + .owner = THIS_MODULE, + .name = "sis5595", + .id = I2C_DRIVERID_SIS5595, + .flags = I2C_DF_NOTIFY, + .attach_adapter = sis5595_attach_adapter, + .detach_client = sis5595_detach_client, +}; + +/* 4 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->in_min[nr] = IN_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->in_max[nr] = IN_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + data->temp_over = TEMP_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + data->temp_hyst = TEMP_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst); + +/* 2 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg = sis5595_read_value(client, SIS5595_REG_FANDIV); + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + return -EINVAL; + } + + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + sis5595_write_value(client, SIS5595_REG_FANDIV, reg); + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +static ssize_t set_fan_1_div(struct device *dev, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} +static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div); +static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This is called when the module is loaded */ +static int sis5595_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, sis5595_detect); +} + +int sis5595_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int err = 0; + int i; + struct i2c_client *new_client; + struct sis5595_data *data; + char val; + u16 a; + + /* Make sure we are probing the ISA bus!! */ + if (!i2c_is_isa_adapter(adapter)) + goto exit; + + if (force_addr) + address = force_addr & ~(SIS5595_EXTENT - 1); + /* Reserve the ISA region */ + if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) { + err = -EBUSY; + goto exit; + } + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) + goto exit_release; + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) + goto exit_release; + if ((a & ~(SIS5595_EXTENT - 1)) != address) + /* doesn't work for some chips? */ + goto exit_release; + } + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) { + goto exit_release; + } + if ((val & 0x80) == 0) { + if (PCIBIOS_SUCCESSFUL != + pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, + val | 0x80)) + goto exit_release; + if (PCIBIOS_SUCCESSFUL != + pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) + goto exit_release; + if ((val & 0x80) == 0) + /* doesn't work for some chips! */ + goto exit_release; + } + + if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct sis5595_data)); + + new_client = &data->client; + new_client->addr = address; + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->adapter = adapter; + new_client->driver = &sis5595_driver; + new_client->flags = 0; + + /* Check revision and pin registers to determine whether 4 or 5 voltages */ + pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); + /* 4 voltages, 1 temp */ + data->maxins = 3; + if (data->revision >= REV2MIN) { + pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); + if (!(val & 0x80)) + /* 5 voltages, no temps */ + data->maxins = 4; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the SIS5595 chip */ + sis5595_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 2; i++) { + data->fan_min[i] = sis5595_read_value(new_client, + SIS5595_REG_FAN_MIN(i)); + } + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + if (data->maxins == 4) { + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + } + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + if (data->maxins == 3) { + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + } + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, SIS5595_EXTENT); +exit: + return err; +} + +static int sis5595_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; + } + + if (i2c_is_isa_client(client)) + release_region(client->addr, SIS5595_EXTENT); + + kfree(i2c_get_clientdata(client)); + + return 0; +} + + +/* ISA access must be locked explicitly. */ +static int sis5595_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + struct sis5595_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); + up(&data->lock); + return res; +} + +static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + struct sis5595_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); + up(&data->lock); + return 0; +} + +/* Called when we have found a new SIS5595. */ +static void sis5595_init_client(struct i2c_client *client) +{ + u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG); + if (!(config & 0x01)) + sis5595_write_value(client, SIS5595_REG_CONFIG, + (config & 0xf7) | 0x01); +} + +static struct sis5595_data *sis5595_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + for (i = 0; i <= data->maxins; i++) { + data->in[i] = + sis5595_read_value(client, SIS5595_REG_IN(i)); + data->in_min[i] = + sis5595_read_value(client, + SIS5595_REG_IN_MIN(i)); + data->in_max[i] = + sis5595_read_value(client, + SIS5595_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) { + data->fan[i] = + sis5595_read_value(client, SIS5595_REG_FAN(i)); + data->fan_min[i] = + sis5595_read_value(client, + SIS5595_REG_FAN_MIN(i)); + } + if (data->maxins == 3) { + data->temp = + sis5595_read_value(client, SIS5595_REG_TEMP); + data->temp_over = + sis5595_read_value(client, SIS5595_REG_TEMP_OVER); + data->temp_hyst = + sis5595_read_value(client, SIS5595_REG_TEMP_HYST); + } + i = sis5595_read_value(client, SIS5595_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + sis5595_read_value(client, SIS5595_REG_ALARM1) | + (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static struct pci_device_id sis5595_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); + +static int blacklist[] __devinitdata = { + PCI_DEVICE_ID_SI_540, + PCI_DEVICE_ID_SI_550, + PCI_DEVICE_ID_SI_630, + PCI_DEVICE_ID_SI_645, + PCI_DEVICE_ID_SI_730, + PCI_DEVICE_ID_SI_735, + PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but + that ID shows up in other chips so we + use the 5511 ID for recognition */ + PCI_DEVICE_ID_SI_5597, + PCI_DEVICE_ID_SI_5598, + 0 }; + +static int __devinit sis5595_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u16 val; + int *i; + int addr = 0; + + for (i = blacklist; *i != 0; i++) { + struct pci_dev *dev; + dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); + if (dev) { + dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); + pci_dev_put(dev); + return -ENODEV; + } + } + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, SIS5595_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(SIS5595_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + + s_bridge = pci_dev_get(dev); + if (i2c_add_driver(&sis5595_driver)) { + pci_dev_put(s_bridge); + s_bridge = NULL; + } + + /* Always return failure here. This is to allow other drivers to bind + * to this pci device. We don't really want to have control over the + * pci device, we only wanted to read as few register values from it. + */ + return -ENODEV; +} + +static struct pci_driver sis5595_pci_driver = { + .name = "sis5595", + .id_table = sis5595_pci_ids, + .probe = sis5595_pci_probe, +}; + +static int __init sm_sis5595_init(void) +{ + return pci_register_driver(&sis5595_pci_driver); +} + +static void __exit sm_sis5595_exit(void) +{ + pci_unregister_driver(&sis5595_pci_driver); + if (s_bridge != NULL) { + i2c_del_driver(&sis5595_driver); + pci_dev_put(s_bridge); + s_bridge = NULL; + } +} + +MODULE_AUTHOR("Aurelien Jarno "); +MODULE_DESCRIPTION("SiS 5595 Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_sis5595_init); +module_exit(sm_sis5595_exit); diff -Nru a/drivers/i2c/chips/smsc47b397.c b/drivers/i2c/chips/smsc47b397.c --- a/drivers/i2c/chips/smsc47b397.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/smsc47b397.c 2005-02-28 17:20:43 -08:00 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -130,9 +131,7 @@ down(&data->update_lock); - if (time_after(jiffies - data->last_updated, (unsigned long)HZ) - || time_before(jiffies, data->last_updated) || !data->valid) { - + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { dev_dbg(&client->dev, "starting device update...\n"); /* 4 temperature inputs, 4 fan inputs */ diff -Nru a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c --- a/drivers/i2c/chips/smsc47m1.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/smsc47m1.c 2005-02-28 17:20:43 -08:00 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -108,7 +109,6 @@ struct smsc47m1_data { struct i2c_client client; struct semaphore lock; - int sysctl_id; struct semaphore update_lock; unsigned long last_updated; /* In jiffies */ @@ -133,8 +133,6 @@ int init); -static int smsc47m1_id; - static struct i2c_driver smsc47m1_driver = { .owner = THIS_MODULE, .name = "smsc47m1", @@ -420,8 +418,6 @@ new_client->flags = 0; strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); - - new_client->id = smsc47m1_id++; init_MUTEX(&data->update_lock); /* If no function is properly configured, there's no point in @@ -532,8 +528,7 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || init) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { int i; for (i = 0; i < 2; i++) { diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c --- a/drivers/i2c/chips/via686a.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/via686a.c 2005-02-28 17:20:43 -08:00 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -726,9 +727,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { for (i = 0; i <= 4; i++) { data->in[i] = via686a_read_value(client, VIA686A_REG_IN(i)); diff -Nru a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c --- a/drivers/i2c/chips/w83627hf.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/w83627hf.c 2005-02-28 17:20:43 -08:00 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1321,6 +1322,27 @@ data->pwmenable[2] = 1; if(init) { + /* Enable temp2 */ + tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ + if (type != w83697hf) { + tmp = w83627hf_read_value(client, + W83781D_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83627hf_write_value(client, + W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); + } + } + if (type == w83627hf) { /* enable PWM2 control (can't hurt since PWM reg should have been reset to 0xff) */ @@ -1350,8 +1372,8 @@ down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { for (i = 0; i <= 8; i++) { /* skip missing sensors */ if (((data->type == w83697hf) && (i == 1)) || diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/w83781d.c 2005-02-28 17:20:43 -08:00 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -1562,11 +1563,28 @@ } #endif /* W83781D_RT */ - if (init) { + if (init && type != as99127f) { + /* Enable temp2 */ + tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ if (type != w83783s && type != w83697hf) { - w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG, - 0x00); + tmp = w83781d_read_value(client, + W83781D_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83781d_write_value(client, + W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); + } } + if (type != w83781d) { /* enable comparator mode for temp2 and temp3 so alarm indication will work correctly */ @@ -1592,9 +1610,8 @@ down(&data->update_lock); - if (time_after - (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2)) - || time_before(jiffies, data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { dev_dbg(dev, "Starting device update\n"); for (i = 0; i <= 8; i++) { diff -Nru a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c --- a/drivers/i2c/chips/w83l785ts.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/chips/w83l785ts.c 2005-02-28 17:20:43 -08:00 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -114,12 +115,6 @@ }; /* - * Internal variables - */ - -static int w83l785ts_id = 0; - -/* * Sysfs stuff */ @@ -229,7 +224,6 @@ /* We can fill in the remaining client fields. */ strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE); - new_client->id = w83l785ts_id++; data->valid = 0; init_MUTEX(&data->update_lock); @@ -301,9 +295,7 @@ down(&data->update_lock); - if (!data->valid - || (jiffies - data->last_updated > HZ * 2) - || (jiffies < data->last_updated)) { + if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { dev_dbg(&client->dev, "Updating w83l785ts data.\n"); data->temp = w83l785ts_read_value(client, W83L785TS_REG_TEMP, data->temp); diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c --- a/drivers/i2c/i2c-core.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/i2c-core.c 2005-02-28 17:20:43 -08:00 @@ -38,12 +38,43 @@ static DECLARE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); -int i2c_device_probe(struct device *dev) +/* match always succeeds, as we want the probe() to tell if we really accept this match */ +static int i2c_device_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int i2c_bus_suspend(struct device * dev, pm_message_t state) +{ + int rc = 0; + + if (dev->driver && dev->driver->suspend) + rc = dev->driver->suspend(dev,state,0); + return rc; +} + +static int i2c_bus_resume(struct device * dev) +{ + int rc = 0; + + if (dev->driver && dev->driver->resume) + rc = dev->driver->resume(dev,0); + return rc; +} + +static struct bus_type i2c_bus_type = { + .name = "i2c", + .match = i2c_device_match, + .suspend = i2c_bus_suspend, + .resume = i2c_bus_resume, +}; + +static int i2c_device_probe(struct device *dev) { return -ENODEV; } -int i2c_device_remove(struct device *dev) +static int i2c_device_remove(struct device *dev) { return 0; } @@ -523,38 +554,6 @@ up(&adap->clist_lock); } - -/* match always succeeds, as we want the probe() to tell if we really accept this match */ -static int i2c_device_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - -static int i2c_bus_suspend(struct device * dev, u32 state) -{ - int rc = 0; - - if (dev->driver && dev->driver->suspend) - rc = dev->driver->suspend(dev,state,0); - return rc; -} - -static int i2c_bus_resume(struct device * dev) -{ - int rc = 0; - - if (dev->driver && dev->driver->resume) - rc = dev->driver->resume(dev,0); - return rc; -} - -struct bus_type i2c_bus_type = { - .name = "i2c", - .match = i2c_device_match, - .suspend = i2c_bus_suspend, - .resume = i2c_bus_resume, -}; - static int __init i2c_init(void) { int retval; @@ -583,7 +582,7 @@ * ---------------------------------------------------- */ -int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) +int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) { int ret; @@ -860,7 +859,7 @@ /* CRC over count bytes in the first array plus the bytes in the rest array if it is non-null. rest[0] is the (length of rest) - 1 and is included. */ -u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) { int i; @@ -872,7 +871,7 @@ return crc; } -u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) { return i2c_smbus_partial_pec(0, count, first, rest); } @@ -880,8 +879,8 @@ /* Returns new "size" (transaction type) Note that we convert byte to byte_data and byte_data to word_data rather than invent new xxx_PEC transactions. */ -int i2c_smbus_add_pec(u16 addr, u8 command, int size, - union i2c_smbus_data *data) +static int i2c_smbus_add_pec(u16 addr, u8 command, int size, + union i2c_smbus_data *data) { u8 buf[3]; @@ -910,8 +909,8 @@ return size; } -int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, - union i2c_smbus_data *data) +static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, + union i2c_smbus_data *data) { u8 buf[3], rpec, cpec; diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c --- a/drivers/i2c/i2c-dev.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/i2c-dev.c 2005-02-28 17:20:43 -08:00 @@ -55,7 +55,7 @@ static struct i2c_dev *i2c_dev_array[I2C_MINORS]; static DEFINE_SPINLOCK(i2c_dev_array_lock); -struct i2c_dev *i2c_dev_get_by_minor(unsigned index) +static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) { struct i2c_dev *i2c_dev; @@ -65,7 +65,7 @@ return i2c_dev; } -struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap) +static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap) { struct i2c_dev *i2c_dev = NULL; @@ -173,8 +173,8 @@ return ret; } -int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int i2cdev_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct i2c_client *client = (struct i2c_client *)file->private_data; struct i2c_rdwr_ioctl_data rdwr_arg; @@ -507,7 +507,6 @@ static struct i2c_client i2cdev_client_template = { .name = "I2C /dev entry", - .id = 1, .addr = -1, .driver = &i2cdev_driver, }; diff -Nru a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c --- a/drivers/i2c/i2c-sensor-detect.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/i2c/i2c-sensor-detect.c 2005-02-28 17:20:43 -08:00 @@ -19,17 +19,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include -#include -#include -#include -#include -#include #include #include -#include static unsigned short empty[] = {I2C_CLIENT_END}; static unsigned int empty_isa[] = {I2C_CLIENT_ISA_END}; diff -Nru a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c --- a/drivers/macintosh/therm_windtunnel.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/macintosh/therm_windtunnel.c 2005-02-28 17:20:43 -08:00 @@ -47,8 +47,6 @@ #define LOG_TEMP 0 /* continously log temperature */ #define I2C_DRIVERID_G4FAN 0x9001 /* fixme */ -#define THERMOSTAT_CLIENT_ID 1 -#define FAN_CLIENT_ID 2 static int do_probe( struct i2c_adapter *adapter, int addr, int kind); @@ -372,7 +370,6 @@ goto out; printk("ADM1030 fan controller [@%02x]\n", cl->addr ); - cl->id = FAN_CLIENT_ID; strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); if( !i2c_attach_client(cl) ) @@ -412,7 +409,6 @@ x.overheat_temp = os_temp; x.overheat_hyst = hyst_temp; - cl->id = THERMOSTAT_CLIENT_ID; strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); if( !i2c_attach_client(cl) ) diff -Nru a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c --- a/drivers/media/common/saa7146_i2c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/common/saa7146_i2c.c 2005-02-28 17:20:43 -08:00 @@ -25,7 +25,7 @@ sent through the saa7146. have a look at the specifications p. 122 ff to understand this. it returns the number of u32s to send, or -1 in case of an error. */ -static int saa7146_i2c_msg_prepare(const struct i2c_msg m[], int num, u32 *op) +static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op) { int h1, h2; int i, j, addr; @@ -89,7 +89,7 @@ which bytes were read through the adapter and write them back to the corresponding i2c-message. but instead, we simply write back all bytes. fixme: this could be improved. */ -static int saa7146_i2c_msg_cleanup(const struct i2c_msg m[], int num, u32 *op) +static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op) { int i, j; int op_count = 0; @@ -272,7 +272,7 @@ return 0; } -int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg msgs[], int num, int retries) +int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; u32* buffer = dev->d_i2c.cpu_addr; @@ -372,7 +372,7 @@ } /* utility functions */ -static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num) +static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) { struct saa7146_dev* dev = i2c_get_adapdata(adapter); diff -Nru a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c --- a/drivers/media/dvb/b2c2/skystar2.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/dvb/b2c2/skystar2.c 2005-02-28 17:20:43 -08:00 @@ -293,7 +293,7 @@ return buf - start; } -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int num) +static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num) { struct adapter *tmp = i2c_get_adapdata(adapter); int i, ret = 0; diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c --- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c 2005-02-28 17:20:43 -08:00 @@ -38,7 +38,7 @@ /* * I2C master xfer function */ -static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) { struct usb_dibusb *dib = i2c_get_adapdata(adap); int i; diff -Nru a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2005-02-28 17:20:43 -08:00 @@ -252,7 +252,7 @@ return rcv_len; } -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msg[], int num) +static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num) { struct ttusb *ttusb = i2c_get_adapdata(adapter); int i = 0; diff -Nru a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c --- a/drivers/media/video/adv7170.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/adv7170.c 2005-02-28 17:20:43 -08:00 @@ -402,7 +402,6 @@ .force = force }; -static int adv7170_i2c_id = 0; static struct i2c_driver i2c_driver_adv7170; static int @@ -432,7 +431,6 @@ client->adapter = adapter; client->driver = &i2c_driver_adv7170; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = adv7170_i2c_id++; if ((client->addr == I2C_ADV7170 >> 1) || (client->addr == (I2C_ADV7170 >> 1) + 1)) { dname = adv7170_name; @@ -444,8 +442,7 @@ kfree(client); return 0; } - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "%s[%d]", dname, client->id); + strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client))); encoder = kmalloc(sizeof(struct adv7170), GFP_KERNEL); if (encoder == NULL) { diff -Nru a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c --- a/drivers/media/video/adv7175.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/adv7175.c 2005-02-28 17:20:43 -08:00 @@ -452,7 +452,6 @@ .force = force }; -static int adv7175_i2c_id = 0; static struct i2c_driver i2c_driver_adv7175; static int @@ -482,7 +481,6 @@ client->adapter = adapter; client->driver = &i2c_driver_adv7175; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = adv7175_i2c_id++; if ((client->addr == I2C_ADV7175 >> 1) || (client->addr == (I2C_ADV7175 >> 1) + 1)) { dname = adv7175_name; @@ -494,8 +492,7 @@ kfree(client); return 0; } - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "%s[%d]", dname, client->id); + strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client))); encoder = kmalloc(sizeof(struct adv7175), GFP_KERNEL); if (encoder == NULL) { diff -Nru a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c --- a/drivers/media/video/bt819.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/bt819.c 2005-02-28 17:20:43 -08:00 @@ -517,7 +517,6 @@ .force = force }; -static int bt819_i2c_id = 0; static struct i2c_driver i2c_driver_bt819; static int @@ -546,7 +545,6 @@ client->adapter = adapter; client->driver = &i2c_driver_bt819; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = bt819_i2c_id++; decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL); if (decoder == NULL) { @@ -568,16 +566,13 @@ id = bt819_read(client, 0x17); switch (id & 0xf0) { case 0x70: - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "bt819a[%d]", client->id); + strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client))); break; case 0x60: - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "bt817a[%d]", client->id); + strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client))); break; case 0x20: - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "bt815a[%d]", client->id); + strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client))); break; default: dprintk(1, diff -Nru a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c --- a/drivers/media/video/bt856.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/bt856.c 2005-02-28 17:20:43 -08:00 @@ -306,7 +306,6 @@ .force = force }; -static int bt856_i2c_id = 0; static struct i2c_driver i2c_driver_bt856; static int @@ -335,9 +334,7 @@ client->adapter = adapter; client->driver = &i2c_driver_bt856; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = bt856_i2c_id++; - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "bt856[%d]", client->id); + strlcpy(I2C_NAME(client), "bt856", sizeof(I2C_NAME(client))); encoder = kmalloc(sizeof(struct bt856), GFP_KERNEL); if (encoder == NULL) { diff -Nru a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c --- a/drivers/media/video/bttv-i2c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/bttv-i2c.c 2005-02-28 17:20:43 -08:00 @@ -245,7 +245,7 @@ return retval; } -static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { struct bttv *btv = i2c_get_adapdata(i2c_adap); int retval = 0; @@ -330,7 +330,6 @@ static struct i2c_client bttv_i2c_client_template = { I2C_DEVNAME("bttv internal"), - .id = -1, }; diff -Nru a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c --- a/drivers/media/video/cx88/cx88-i2c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/cx88/cx88-i2c.c 2005-02-28 17:20:43 -08:00 @@ -141,7 +141,6 @@ static struct i2c_client cx8800_i2c_client_template = { I2C_DEVNAME("cx88xx internal"), - .id = -1, }; static char *i2c_devs[128] = { diff -Nru a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c --- a/drivers/media/video/ovcamchip/ovcamchip_core.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c 2005-02-28 17:20:43 -08:00 @@ -422,7 +422,6 @@ static struct i2c_client client_template = { I2C_DEVNAME("(unset)"), - .id = -1, .driver = &driver, }; diff -Nru a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c --- a/drivers/media/video/saa5246a.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa5246a.c 2005-02-28 17:20:43 -08:00 @@ -185,7 +185,6 @@ }; static struct i2c_client client_template = { - .id = -1, .driver = &i2c_driver_videotext, .name = "(unset)", }; diff -Nru a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c --- a/drivers/media/video/saa5249.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa5249.c 2005-02-28 17:20:43 -08:00 @@ -258,7 +258,6 @@ }; static struct i2c_client client_template = { - .id = -1, .driver = &i2c_driver_videotext, .name = "(unset)", }; diff -Nru a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c --- a/drivers/media/video/saa7110.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa7110.c 2005-02-28 17:20:43 -08:00 @@ -476,7 +476,6 @@ .force = force }; -static int saa7110_i2c_id = 0; static struct i2c_driver i2c_driver_saa7110; static int @@ -507,9 +506,7 @@ client->adapter = adapter; client->driver = &i2c_driver_saa7110; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = saa7110_i2c_id++; - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "saa7110[%d]", client->id); + strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client))); decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); if (decoder == 0) { diff -Nru a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c --- a/drivers/media/video/saa7111.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa7111.c 2005-02-28 17:20:43 -08:00 @@ -500,7 +500,6 @@ .force = force }; -static int saa7111_i2c_id = 0; static struct i2c_driver i2c_driver_saa7111; static int @@ -530,9 +529,7 @@ client->adapter = adapter; client->driver = &i2c_driver_saa7111; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = saa7111_i2c_id++; - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "saa7111[%d]", client->id); + strlcpy(I2C_NAME(client), "saa7111", sizeof(I2C_NAME(client))); decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); if (decoder == NULL) { diff -Nru a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c --- a/drivers/media/video/saa7114.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa7114.c 2005-02-28 17:20:43 -08:00 @@ -838,7 +838,6 @@ .force = force }; -static int saa7114_i2c_id = 0; static struct i2c_driver i2c_driver_saa7114; static int @@ -871,9 +870,7 @@ client->adapter = adapter; client->driver = &i2c_driver_saa7114; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = saa7114_i2c_id++; - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "saa7114[%d]", client->id); + strlcpy(I2C_NAME(client), "saa7114", sizeof(I2C_NAME(client))); decoder = kmalloc(sizeof(struct saa7114), GFP_KERNEL); if (decoder == NULL) { diff -Nru a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c --- a/drivers/media/video/saa7134/saa7134-i2c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa7134/saa7134-i2c.c 2005-02-28 17:20:43 -08:00 @@ -236,7 +236,7 @@ } static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) + struct i2c_msg *msgs, int num) { struct saa7134_dev *dev = i2c_adap->algo_data; enum i2c_status status; @@ -362,7 +362,6 @@ static struct i2c_client saa7134_client_template = { I2C_DEVNAME("saa7134 internal"), - .id = -1, }; /* ----------------------------------------------------------- */ diff -Nru a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c --- a/drivers/media/video/saa7185.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/saa7185.c 2005-02-28 17:20:43 -08:00 @@ -398,7 +398,6 @@ .force = force }; -static int saa7185_i2c_id = 0; static struct i2c_driver i2c_driver_saa7185; static int @@ -427,9 +426,7 @@ client->adapter = adapter; client->driver = &i2c_driver_saa7185; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = saa7185_i2c_id++; - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "saa7185[%d]", client->id); + strlcpy(I2C_NAME(client), "saa7185", sizeof(I2C_NAME(client))); encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); if (encoder == NULL) { diff -Nru a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c --- a/drivers/media/video/tda7432.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/tda7432.c 2005-02-28 17:20:43 -08:00 @@ -528,7 +528,6 @@ static struct i2c_client client_template = { I2C_DEVNAME("tda7432"), - .id = -1, .driver = &driver, }; diff -Nru a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c --- a/drivers/media/video/tda9840.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/tda9840.c 2005-02-28 17:20:43 -08:00 @@ -51,9 +51,6 @@ static struct i2c_driver driver; static struct i2c_client client_template; -/* unique ID allocation */ -static int tda9840_id = 0; - static int command(struct i2c_client *client, unsigned int cmd, void *arg) { int result; @@ -179,7 +176,6 @@ /* fill client structure */ memcpy(client, &client_template, sizeof(struct i2c_client)); - client->id = tda9840_id++; client->addr = address; client->adapter = adapter; diff -Nru a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c --- a/drivers/media/video/tda9875.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/tda9875.c 2005-02-28 17:20:43 -08:00 @@ -399,7 +399,6 @@ static struct i2c_client client_template = { I2C_DEVNAME("tda9875"), - .id = -1, .driver = &driver, }; diff -Nru a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c --- a/drivers/media/video/tea6415c.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/tea6415c.c 2005-02-28 17:20:43 -08:00 @@ -51,9 +51,6 @@ static struct i2c_driver driver; static struct i2c_client client_template; -/* unique ID allocation */ -static int tea6415c_id = 0; - /* this function is called by i2c_probe */ static int detect(struct i2c_adapter *adapter, int address, int kind) { @@ -73,7 +70,6 @@ /* fill client structure */ memcpy(client, &client_template, sizeof(struct i2c_client)); - client->id = tea6415c_id++; client->addr = address; client->adapter = adapter; diff -Nru a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c --- a/drivers/media/video/tea6420.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/tea6420.c 2005-02-28 17:20:43 -08:00 @@ -48,9 +48,6 @@ static struct i2c_driver driver; static struct i2c_client client_template; -/* unique ID allocation */ -static int tea6420_id = 0; - /* make a connection between the input 'i' and the output 'o' with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */ static int tea6420_switch(struct i2c_client *client, int i, int o, int g) @@ -111,7 +108,6 @@ /* fill client structure */ memcpy(client, &client_template, sizeof(struct i2c_client)); - client->id = tea6420_id++; client->addr = address; client->adapter = adapter; diff -Nru a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c --- a/drivers/media/video/tuner-3036.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/tuner-3036.c 2005-02-28 17:20:43 -08:00 @@ -192,7 +192,6 @@ static struct i2c_client client_template = { - .id = -1, .driver = &i2c_driver_tuner, .name = "SAB3036", }; diff -Nru a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c --- a/drivers/media/video/vpx3220.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/media/video/vpx3220.c 2005-02-28 17:20:43 -08:00 @@ -587,7 +587,6 @@ .force = force }; -static int vpx3220_i2c_id = 0; static struct i2c_driver vpx3220_i2c_driver; static int @@ -634,7 +633,6 @@ client->adapter = adapter; client->driver = &vpx3220_i2c_driver; client->flags = I2C_CLIENT_ALLOW_USE; - client->id = vpx3220_i2c_id++; /* Check for manufacture ID and part number */ if (kind < 0) { @@ -655,16 +653,16 @@ vpx3220_read(client, 0x01); switch (pn) { case 0x4680: - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "vpx3220a[%d]", client->id); + strlcpy(I2C_NAME(client), "vpx3220a", + sizeof(I2C_NAME(client))); break; case 0x4260: - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "vpx3216b[%d]", client->id); + strlcpy(I2C_NAME(client), "vpx3216b", + sizeof(I2C_NAME(client))); break; case 0x4280: - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "vpx3214c[%d]", client->id); + strlcpy(I2C_NAME(client), "vpx3214c", + sizeof(I2C_NAME(client))); break; default: dprintk(1, @@ -675,9 +673,8 @@ return 0; } } else { - snprintf(I2C_NAME(client), sizeof(I2C_NAME(client)) - 1, - "forced vpx32xx[%d]", - client->id); + strlcpy(I2C_NAME(client), "forced vpx32xx", + sizeof(I2C_NAME(client))); } decoder = kmalloc(sizeof(struct vpx3220), GFP_KERNEL); diff -Nru a/drivers/superio/Kconfig b/drivers/superio/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/superio/Kconfig 2005-02-28 17:20:43 -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-02-28 17:20:43 -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-02-28 17:20:43 -08:00 @@ -0,0 +1,52 @@ +/* + * chain.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include + +#include +#include + +#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-02-28 17:20:43 -08:00 @@ -0,0 +1,37 @@ +/* + * chain.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 + +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-02-28 17:20:43 -08:00 @@ -0,0 +1,209 @@ +/* + * pc8736x.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sc.h" +#include "pc8736x.h" +#include "sc_gpio.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +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-02-28 17:20:43 -08:00 @@ -0,0 +1,39 @@ +/* + * pc8736x.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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-02-28 17:20:43 -08:00 @@ -0,0 +1,93 @@ +/* + * pin_test.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#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; iread(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; icontrol(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-02-28 17:20:43 -08:00 @@ -0,0 +1,802 @@ +/* + * sc.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sc.h" +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +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-02-28 17:20:43 -08:00 @@ -0,0 +1,134 @@ +/* + * sc.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include + +#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-02-28 17:20:43 -08:00 @@ -0,0 +1,158 @@ +/* + * sc_acb.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include + +#include + +#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 "); +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-02-28 17:20:43 -08:00 @@ -0,0 +1,45 @@ +/* + * sc_acb.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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-02-28 17:20:43 -08:00 @@ -0,0 +1,124 @@ +/* + * sc_conn.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include + +#include + +#include "sc.h" +#include + +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-02-28 17:20:43 -08:00 @@ -0,0 +1,312 @@ +/* + * sc_gpio.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include + +#include + +#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<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 "); +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-02-28 17:20:43 -08:00 @@ -0,0 +1,50 @@ +/* + * sc_gpio.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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-02-28 17:20:43 -08:00 @@ -0,0 +1,107 @@ +/* + * sc_w1.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#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 "); +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-02-28 17:20:43 -08:00 @@ -0,0 +1,413 @@ +/* + * scx.c + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sc.h" +#include "scx.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +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-02-28 17:20:43 -08:00 @@ -0,0 +1,28 @@ +/* + * scx.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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/dscore.c b/drivers/w1/dscore.c --- a/drivers/w1/dscore.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/dscore.c 2005-02-28 17:20:43 -08:00 @@ -45,9 +45,6 @@ int ds_reset(struct ds_device *, struct ds_status *); int ds_detect(struct ds_device *, struct ds_status *); int ds_stop_pulse(struct ds_device *, int); -int ds_send_data(struct ds_device *, unsigned char *, int); -int ds_recv_data(struct ds_device *, unsigned char *, int); -int ds_recv_status(struct ds_device *, struct ds_status *); struct ds_device * ds_get_device(void); void ds_put_device(struct ds_device *); @@ -148,7 +145,7 @@ return count; } -int ds_recv_status(struct ds_device *dev, struct ds_status *st) +static int ds_recv_status(struct ds_device *dev, struct ds_status *st) { unsigned char buf[64]; int count, err = 0, i; @@ -206,7 +203,7 @@ return err; } -int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) +static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size) { int count, err; struct ds_status st; @@ -234,7 +231,7 @@ return count; } -int ds_send_data(struct ds_device *dev, unsigned char *buf, int len) +static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len) { int count, err; @@ -774,15 +771,19 @@ EXPORT_SYMBOL(ds_write_byte); EXPORT_SYMBOL(ds_write_bit); EXPORT_SYMBOL(ds_write_block); +EXPORT_SYMBOL(ds_reset); +EXPORT_SYMBOL(ds_get_device); +EXPORT_SYMBOL(ds_put_device); + +/* + * This functions can be used for EEPROM programming, + * when driver will be included into mainline this will + * require uncommenting. + */ +#if 0 EXPORT_SYMBOL(ds_start_pulse); EXPORT_SYMBOL(ds_set_speed); -EXPORT_SYMBOL(ds_reset); EXPORT_SYMBOL(ds_detect); EXPORT_SYMBOL(ds_stop_pulse); -EXPORT_SYMBOL(ds_send_data); -EXPORT_SYMBOL(ds_recv_data); -EXPORT_SYMBOL(ds_recv_status); EXPORT_SYMBOL(ds_search); -EXPORT_SYMBOL(ds_get_device); -EXPORT_SYMBOL(ds_put_device); - +#endif diff -Nru a/drivers/w1/dscore.h b/drivers/w1/dscore.h --- a/drivers/w1/dscore.h 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/dscore.h 2005-02-28 17:20:43 -08:00 @@ -161,9 +161,6 @@ int ds_reset(struct ds_device *, struct ds_status *); int ds_detect(struct ds_device *, struct ds_status *); int ds_stop_pulse(struct ds_device *, int); -int ds_send_data(struct ds_device *, unsigned char *, int); -int ds_recv_data(struct ds_device *, unsigned char *, int); -int ds_recv_status(struct ds_device *, struct ds_status *); struct ds_device * ds_get_device(void); void ds_put_device(struct ds_device *); int ds_write_block(struct ds_device *, u8 *, int); diff -Nru a/drivers/w1/matrox_w1.c b/drivers/w1/matrox_w1.c --- a/drivers/w1/matrox_w1.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/matrox_w1.c 2005-02-28 17:20:43 -08:00 @@ -235,7 +235,7 @@ static int __init matrox_w1_init(void) { - return pci_module_init(&matrox_w1_pci_driver); + return pci_register_driver(&matrox_w1_pci_driver); } static void __exit matrox_w1_fini(void) diff -Nru a/drivers/w1/w1.c b/drivers/w1/w1.c --- a/drivers/w1/w1.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/w1.c 2005-02-28 17:20:43 -08:00 @@ -19,8 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include - #include #include #include @@ -33,6 +31,8 @@ #include #include +#include + #include "w1.h" #include "w1_io.h" #include "w1_log.h" @@ -58,7 +58,6 @@ static pid_t control_thread; static int control_needs_exit; static DECLARE_COMPLETION(w1_control_complete); -static DECLARE_WAIT_QUEUE_HEAD(w1_control_wait); static int w1_master_match(struct device *dev, struct device_driver *drv) { @@ -100,7 +99,7 @@ return sprintf(buf, "No family registered.\n"); } -struct bus_type w1_bus_type = { +static struct bus_type w1_bus_type = { .name = "w1", .match = w1_master_match, }; @@ -138,7 +137,7 @@ .show = &w1_default_read_name, }; -ssize_t w1_master_attribute_show_name(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf) { struct w1_master *md = container_of (dev, struct w1_master, dev); ssize_t count; @@ -153,7 +152,7 @@ return count; } -ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -167,14 +166,14 @@ return count; } -ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf) { ssize_t count; count = sprintf(buf, "%d\n", w1_timeout); return count; } -ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -188,7 +187,7 @@ return count; } -ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -202,7 +201,7 @@ return count; } -ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); ssize_t count; @@ -216,7 +215,7 @@ return count; } -ssize_t w1_master_attribute_show_slaves(struct device *dev, char *buf) +static ssize_t w1_master_attribute_show_slaves(struct device *dev, char *buf) { struct w1_master *md = container_of(dev, struct w1_master, dev); @@ -649,7 +648,7 @@ struct w1_slave *sl; struct w1_master *dev; struct list_head *ent, *ment, *n, *mn; - int err, have_to_wait = 0, timeout; + int err, have_to_wait = 0; daemonize("w1_control"); allow_signal(SIGTERM); @@ -657,11 +656,8 @@ while (!control_needs_exit || have_to_wait) { have_to_wait = 0; - timeout = w1_timeout*HZ; - do { - timeout = interruptible_sleep_on_timeout(&w1_control_wait, timeout); - try_to_freeze(PF_FREEZE); - } while (!signal_pending(current) && (timeout > 0)); + try_to_freeze(PF_FREEZE); + msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) flush_signals(current); @@ -721,7 +717,6 @@ int w1_process(void *data) { struct w1_master *dev = (struct w1_master *) data; - unsigned long timeout; struct list_head *ent, *n; struct w1_slave *sl; @@ -729,11 +724,8 @@ allow_signal(SIGTERM); while (!dev->need_exit) { - timeout = w1_timeout*HZ; - do { - timeout = interruptible_sleep_on_timeout(&dev->kwait, timeout); - try_to_freeze(PF_FREEZE); - } while (!signal_pending(current) && (timeout > 0)); + try_to_freeze(PF_FREEZE); + msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) flush_signals(current); @@ -839,6 +831,3 @@ module_init(w1_init); module_exit(w1_fini); - -EXPORT_SYMBOL(w1_create_master_attributes); -EXPORT_SYMBOL(w1_destroy_master_attributes); diff -Nru a/drivers/w1/w1.h b/drivers/w1/w1.h --- a/drivers/w1/w1.h 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/w1.h 2005-02-28 17:20:43 -08:00 @@ -115,7 +115,6 @@ int need_exit; pid_t kpid; - wait_queue_head_t kwait; struct semaphore mutex; struct device_driver *driver; diff -Nru a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c --- a/drivers/w1/w1_family.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/w1_family.c 2005-02-28 17:20:43 -08:00 @@ -138,13 +138,13 @@ void __w1_family_get(struct w1_family *f) { + smp_mb__before_atomic_inc(); atomic_inc(&f->refcnt); + smp_mb__after_atomic_inc(); } EXPORT_SYMBOL(w1_family_get); EXPORT_SYMBOL(w1_family_put); -EXPORT_SYMBOL(__w1_family_get); -EXPORT_SYMBOL(__w1_family_put); EXPORT_SYMBOL(w1_family_registered); EXPORT_SYMBOL(w1_unregister_family); EXPORT_SYMBOL(w1_register_family); diff -Nru a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c --- a/drivers/w1/w1_int.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/w1_int.c 2005-02-28 17:20:43 -08:00 @@ -74,7 +74,6 @@ INIT_LIST_HEAD(&dev->slist); init_MUTEX(&dev->mutex); - init_waitqueue_head(&dev->kwait); init_completion(&dev->dev_released); init_completion(&dev->dev_exited); @@ -217,8 +216,5 @@ __w1_remove_master_device(dev); } -EXPORT_SYMBOL(w1_alloc_dev); -EXPORT_SYMBOL(w1_free_dev); EXPORT_SYMBOL(w1_add_master_device); EXPORT_SYMBOL(w1_remove_master_device); -EXPORT_SYMBOL(__w1_remove_master_device); diff -Nru a/drivers/w1/w1_therm.c b/drivers/w1/w1_therm.c --- a/drivers/w1/w1_therm.c 2005-02-28 17:20:43 -08:00 +++ b/drivers/w1/w1_therm.c 2005-02-28 17:20:43 -08:00 @@ -26,6 +26,7 @@ #include #include #include +#include #include "w1.h" #include "w1_io.h" @@ -103,6 +104,7 @@ int i, max_trying = 10; atomic_inc(&sl->refcnt); + smp_mb__after_atomic_inc(); if (down_interruptible(&sl->master->mutex)) { count = 0; goto out_dec; @@ -128,7 +130,7 @@ if (!w1_reset_bus (dev)) { int count = 0; u8 match[9] = {W1_MATCH_ROM, }; - unsigned long tm; + unsigned int tm = 750; memcpy(&match[1], (u64 *) & sl->reg_num, 8); @@ -136,11 +138,8 @@ w1_write_8(dev, W1_CONVERT_TEMP); - tm = jiffies + msecs_to_jiffies(750); - while(time_before(jiffies, tm)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(tm-jiffies); - + while (tm) { + tm = msleep_interruptible(tm); if (signal_pending(current)) flush_signals(current); } @@ -181,6 +180,7 @@ out: up(&dev->mutex); out_dec: + smp_mb__before_atomic_inc(); atomic_dec(&sl->refcnt); return count; 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-02-28 17:20:43 -08:00 @@ -0,0 +1,150 @@ +/* + * connector.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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 + +#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 + +#include +#include + +#include + +#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-id.h b/include/linux/i2c-id.h --- a/include/linux/i2c-id.h 2005-02-28 17:20:43 -08:00 +++ b/include/linux/i2c-id.h 2005-02-28 17:20:43 -08:00 @@ -20,8 +20,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-id.h,v 1.68 2003/02/25 02:55:18 mds Exp $ */ - #ifndef LINUX_I2C_ID_H #define LINUX_I2C_ID_H @@ -196,11 +194,15 @@ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ #define I2C_ALGO_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ -#define I2C_ALGO_PCA 0x150000 /* PCA 9564 style adapters */ - #define I2C_ALGO_SIBYTE 0x150000 /* Broadcom SiByte SOCs */ -#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ -#define I2C_ALGO_AU1550 0x170000 /* Au1550 PSC algorithm */ +#define I2C_ALGO_SGI 0x160000 /* SGI algorithm */ + +#define I2C_ALGO_USB 0x170000 /* USB algorithm */ +#define I2C_ALGO_VIRT 0x180000 /* Virtual bus adapter */ + +#define I2C_ALGO_MV64XXX 0x190000 /* Marvell mv64xxx i2c ctlr */ +#define I2C_ALGO_PCA 0x1a0000 /* PCA 9564 style adapters */ +#define I2C_ALGO_AU1550 0x1b0000 /* Au1550 PSC algorithm */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -240,6 +242,7 @@ #define I2C_HW_B_IXP4XX 0x17 /* GPIO on IXP4XX systems */ #define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */ #define I2C_HW_B_ZR36067 0x19 /* Zoran-36057/36067 based boards */ +#define I2C_HW_B_PCILYNX 0x1a /* TI PCILynx I2C adapter */ #define I2C_HW_B_CX2388x 0x1b /* connexant 2388x based tv cards */ /* --- PCF 8584 based algorithms */ @@ -309,5 +312,8 @@ /* --- MCP107 adapter */ #define I2C_HW_MPC107 0x00 + +/* --- Marvell mv64xxx i2c adapter */ +#define I2C_HW_MV64XXX 0x00 #endif /* LINUX_I2C_ID_H */ diff -Nru a/include/linux/i2c.h b/include/linux/i2c.h --- a/include/linux/i2c.h 2005-02-28 17:20:43 -08:00 +++ b/include/linux/i2c.h 2005-02-28 17:20:43 -08:00 @@ -55,7 +55,7 @@ /* Transfer num messages. */ -extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num); +extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); /* * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. @@ -134,8 +134,6 @@ }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) -extern struct bus_type i2c_bus_type; - #define I2C_NAME_SIZE 50 /* @@ -144,7 +142,6 @@ * function is mainly used for lookup & other admin. functions. */ struct i2c_client { - int id; unsigned int flags; /* div., see below */ unsigned int addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ @@ -190,11 +187,11 @@ char name[32]; /* textual description */ unsigned int id; - /* If an adapter algorithm can't to I2C-level access, set master_xfer + /* If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ - int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], + int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, int num); int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, @@ -302,8 +299,8 @@ }; /* Internal numbers to terminate lists */ -#define I2C_CLIENT_END 0xfffe -#define I2C_CLIENT_ISA_END 0xfffefffe +#define I2C_CLIENT_END 0xfffeU +#define I2C_CLIENT_ISA_END 0xfffefffeU /* The numbers to use to set I2C bus address */ #define ANY_I2C_BUS 0xffff @@ -423,22 +420,22 @@ #define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ -#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ - I2C_FUNC_SMBUS_WRITE_BYTE -#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \ - I2C_FUNC_SMBUS_WRITE_BYTE_DATA -#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA -#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA -#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK -#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 -#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC -#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ + I2C_FUNC_SMBUS_WRITE_BYTE) +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ + I2C_FUNC_SMBUS_WRITE_BYTE_DATA) +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA) +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) +#define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2) +#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC (I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC) +#define I2C_FUNC_SMBUS_WORD_DATA_PEC (I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC) #define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA #define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA @@ -447,14 +444,14 @@ #define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA #define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA -#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ - I2C_FUNC_SMBUS_BYTE | \ - I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA | \ - I2C_FUNC_SMBUS_PROC_CALL | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ - I2C_FUNC_SMBUS_I2C_BLOCK +#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_PROC_CALL | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_I2C_BLOCK) /* * Data for SMBus Messages diff -Nru a/include/linux/mv643xx.h b/include/linux/mv643xx.h --- a/include/linux/mv643xx.h 2005-02-28 17:20:43 -08:00 +++ b/include/linux/mv643xx.h 2005-02-28 17:20:43 -08:00 @@ -977,12 +977,9 @@ /* I2C Registers */ /****************************************/ -#define MV64340_I2C_SLAVE_ADDR 0xc000 -#define MV64340_I2C_EXTENDED_SLAVE_ADDR 0xc010 -#define MV64340_I2C_DATA 0xc004 -#define MV64340_I2C_CONTROL 0xc008 -#define MV64340_I2C_STATUS_BAUDE_RATE 0xc00C -#define MV64340_I2C_SOFT_RESET 0xc01c +#define MV64XXX_I2C_CTLR_NAME "mv64xxx i2c" +#define MV64XXX_I2C_OFFSET 0xc000 +#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020 /****************************************/ /* GPP Interface Registers */ @@ -1083,6 +1080,14 @@ u8 brg_can_tune; u8 brg_clk_src; u32 brg_clk_freq; +}; + +/* i2c Platform Device, Driver Data */ +struct mv64xxx_i2c_pdata { + u32 freq_m; + u32 freq_n; + u32 timeout; /* In milliseconds */ + u32 retries; }; #endif /* __ASM_MV64340_H */ diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h 2005-02-28 17:20:43 -08:00 +++ b/include/linux/pci_ids.h 2005-02-28 17:20:43 -08:00 @@ -1098,6 +1098,7 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037 #define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e +#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 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-02-28 17:20:43 -08:00 @@ -0,0 +1,50 @@ +/* + * sc_conn.h + * + * 2004 Copyright (c) Evgeniy Polyakov + * 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/include/media/saa7146.h b/include/media/saa7146.h --- a/include/media/saa7146.h 2005-02-28 17:20:43 -08:00 +++ b/include/media/saa7146.h 2005-02-28 17:20:43 -08:00 @@ -157,7 +157,7 @@ /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg msgs[], int num, int retries); +int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct *i2c_msg msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; diff -Nru a/lib/kobject_uevent.c b/lib/kobject_uevent.c --- a/lib/kobject_uevent.c 2005-02-28 17:20:43 -08:00 +++ b/lib/kobject_uevent.c 2005-02-28 17:20:43 -08:00 @@ -12,6 +12,7 @@ * Kay Sievers * Arjan van de Ven * Greg Kroah-Hartman + * Evgeniy Polyakov */ #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #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); } diff -Nru a/sound/oss/dmasound/dac3550a.c b/sound/oss/dmasound/dac3550a.c --- a/sound/oss/dmasound/dac3550a.c 2005-02-28 17:20:43 -08:00 +++ b/sound/oss/dmasound/dac3550a.c 2005-02-28 17:20:43 -08:00 @@ -40,9 +40,6 @@ static int daca_detect_client(struct i2c_adapter *adapter, int address); static int daca_detach_client(struct i2c_client *client); -/* Unique ID allocation */ -static int daca_id; - struct i2c_driver daca_driver = { .owner = THIS_MODULE, .name = "DAC3550A driver V " DACA_VERSION, @@ -176,7 +173,6 @@ new_client->driver = &daca_driver; new_client->flags = 0; strcpy(new_client->name, client_name); - new_client->id = daca_id++; /* racy... */ if (daca_init_client(new_client)) goto bail; diff -Nru a/sound/ppc/keywest.c b/sound/ppc/keywest.c --- a/sound/ppc/keywest.c 2005-02-28 17:20:43 -08:00 +++ b/sound/ppc/keywest.c 2005-02-28 17:20:43 -08:00 @@ -76,8 +76,6 @@ new_client->flags = 0; strcpy(i2c_device_name(new_client), keywest_ctx->name); - - new_client->id = keywest_ctx->id++; /* Automatically unique */ keywest_ctx->client = new_client; /* Tell the i2c layer a new client has arrived */