bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 khali@linux-fr.org|ChangeSet|20050125062835|42001 khali # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/01/28 15:15:39-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # drivers/media/video/saa5249.c # 2005/01/28 15:15:34-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/media/video/saa5246a.c # 2005/01/28 15:15:34-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/media/video/cx88/cx88-i2c.c # 2005/01/28 15:15:34-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/media/video/bttv-i2c.c # 2005/01/28 15:15:34-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/26 18:52:31-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into bix.(none):/usr/src/bk-i2c # # drivers/i2c/i2c-dev.c # 2005/01/26 18:52:26-08:00 akpm@bix.(none) +0 -0 # Auto merged # # 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/21 23:12:47-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-i2c # # drivers/i2c/i2c-dev.c # 2005/01/21 23:12:43-08:00 akpm@bix.(none) +0 -0 # Auto merged # # 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 # # ChangeSet # 2005/01/18 01:58:36-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into bix.(none):/usr/src/bk-i2c # # drivers/i2c/busses/Kconfig # 2005/01/18 01:58:32-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/15 20:47:44-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6 # into bix.(none):/usr/src/bk-i2c # # drivers/i2c/busses/Kconfig # 2005/01/15 20:47:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # diff -Nru a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients --- a/Documentation/i2c/porting-clients 2005-01-28 15:18:53 -08:00 +++ b/Documentation/i2c/porting-clients 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/Documentation/i2c/writing-clients 2005-01-28 15:18:53 -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 */ diff -Nru a/drivers/Kconfig b/drivers/Kconfig --- a/drivers/Kconfig 2005-01-28 15:18:53 -08:00 +++ b/drivers/Kconfig 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/Makefile 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/acorn/char/i2c.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/acorn/char/pcf8583.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -08:00 @@ -0,0 +1,219 @@ +/* + * 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; + + atomic_inc(&cbq->cb->refcnt); + cbq->cb->callback(cbq->cb->priv); + atomic_dec(&cbq->cb->refcnt); + + 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); + 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) { + atomic_dec(&dev->refcnt); + 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) { + atomic_dec(&cbq->cb->refcnt); + cn_queue_free_callback(cbq); + atomic_dec(&dev->refcnt); + } +} + +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); + atomic_dec(&cbq->cb->refcnt); + } + 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-01-28 15:18:53 -08:00 @@ -0,0 +1,509 @@ +/* + * 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); + +spinlock_t notify_lock = SPIN_LOCK_UNLOCKED; +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; + 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; + 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)); + 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"); + 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) { + printk(KERN_INFO "nlmsg_len=%u, sizeof(*nlh)=%u\n", + nlh->nlmsg_len, sizeof(*nlh)); + 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 + kfree_skb(skb); + break; + } else { +#if 0 + if (nlh->nlmsg_flags & NLM_F_ACK) + netlink_ack(skb, nlh, 0); +#endif + kfree_skb(skb); + break; + } + skb_pull(skb, len); + } +} + +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/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c --- a/drivers/i2c/busses/i2c-sis5595.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/busses/i2c-sis5595.c 2005-01-28 15:18:53 -08:00 @@ -181,9 +181,11 @@ if (force_addr) { dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base); - if (!pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)) + if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base) + != PCIBIOS_SUCCESSFUL) goto error; - if (!pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)) + if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a) + != PCIBIOS_SUCCESSFUL) goto error; if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) { /* doesn't work for some chips! */ @@ -192,13 +194,16 @@ } } - if (!pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)) + if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val) + != PCIBIOS_SUCCESSFUL) goto error; if ((val & 0x80) == 0) { dev_info(&SIS5595_dev->dev, "enabling ACPI\n"); - if (!pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80)) + if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80) + != PCIBIOS_SUCCESSFUL) goto error; - if (!pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)) + if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val) + != PCIBIOS_SUCCESSFUL) goto error; if ((val & 0x80) == 0) { /* doesn't work for some chips? */ diff -Nru a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c --- a/drivers/i2c/busses/i2c-viapro.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/busses/i2c-viapro.c 2005-01-28 15:18:53 -08:00 @@ -45,6 +45,8 @@ #include #include +static struct pci_dev *vt596_pdev; + #define SMBBA1 0x90 #define SMBBA2 0x80 #define SMBBA3 0xD0 @@ -381,19 +383,23 @@ snprintf(vt596_adapter.name, I2C_NAME_SIZE, "SMBus Via Pro adapter at %04x", vt596_smba); - return i2c_add_adapter(&vt596_adapter); + vt596_pdev = pci_dev_get(pdev); + if (i2c_add_adapter(&vt596_adapter)) { + pci_dev_put(vt596_pdev); + vt596_pdev = 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; release_region: release_region(vt596_smba, 8); return error; } -static void __devexit vt596_remove(struct pci_dev *pdev) -{ - i2c_del_adapter(&vt596_adapter); - release_region(vt596_smba, 8); -} - static struct pci_device_id vt596_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3), .driver_data = SMBBA1 }, @@ -420,7 +426,6 @@ .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, - .remove = __devexit_p(vt596_remove), }; static int __init i2c_vt596_init(void) @@ -432,6 +437,12 @@ static void __exit i2c_vt596_exit(void) { pci_unregister_driver(&vt596_driver); + if (vt596_pdev != NULL) { + i2c_del_adapter(&vt596_adapter); + release_region(vt596_smba, 8); + pci_dev_put(vt596_pdev); + vt596_pdev = NULL; + } } MODULE_AUTHOR( diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/Kconfig 2005-01-28 15:18:53 -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 diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/Makefile 2005-01-28 15:18:53 -08:00 @@ -14,6 +14,7 @@ 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_IT87) += it87.o obj-$(CONFIG_SENSORS_LM63) += lm63.o diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/adm1021.c 2005-01-28 15:18:53 -08:00 @@ -147,8 +147,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 +297,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); diff -Nru a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c --- a/drivers/i2c/chips/adm1025.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/adm1025.c 2005-01-28 15:18:53 -08:00 @@ -148,12 +148,6 @@ }; /* - * Internal variables - */ - -static int adm1025_id; - -/* * Sysfs stuff */ @@ -397,7 +391,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); diff -Nru a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c --- a/drivers/i2c/chips/adm1026.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/adm1026.c 2005-01-28 15:18:53 -08:00 @@ -313,8 +313,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 +361,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 +419,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 +443,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 +461,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"); } } @@ -582,8 +575,7 @@ if (!data->valid || (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]); @@ -631,8 +623,7 @@ if (!data->valid || (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 +703,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 +1598,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-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/adm1031.c 2005-01-28 15:18:53 -08:00 @@ -110,8 +110,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 +779,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); diff -Nru a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c --- a/drivers/i2c/chips/ds1621.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/ds1621.c 2005-01-28 15:18:53 -08:00 @@ -42,9 +42,8 @@ /* Many DS1621 constants specified below */ /* Config register used for detection */ /* 7 6 5 4 3 2 1 0 */ -/* |Done|THF |TLF |NVB | 1 | 0 |POL |1SHOT| */ -#define DS1621_REG_CONFIG_MASK 0x0C -#define DS1621_REG_CONFIG_VAL 0x08 +/* |Done|THF |TLF |NVB | X | X |POL |1SHOT| */ +#define DS1621_REG_CONFIG_NVB 0x10 #define DS1621_REG_CONFIG_POLARITY 0x02 #define DS1621_REG_CONFIG_1SHOT 0x01 #define DS1621_REG_CONFIG_DONE 0x80 @@ -55,6 +54,7 @@ #define DS1621_REG_TEMP_MAX 0xA2 /* word, RW */ #define DS1621_REG_CONF 0xAC /* byte, RW */ #define DS1621_COM_START 0xEE /* no data */ +#define DS1621_COM_STOP 0x22 /* no data */ /* The DS1621 configuration register */ #define DS1621_ALARM_TEMP_HIGH 0x40 @@ -95,8 +95,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. */ @@ -212,9 +210,13 @@ /* Now, we do the remaining detection. It is lousy. */ if (kind < 0) { + /* The NVB bit should be low if no EEPROM write has been + requested during the latest 10ms, which is highly + improbable in our case. */ conf = ds1621_read_value(new_client, DS1621_REG_CONF); - if ((conf & DS1621_REG_CONFIG_MASK) != DS1621_REG_CONFIG_VAL) + if (conf & DS1621_REG_CONFIG_NVB) goto exit_free; + /* The 7 lowest bits of a temperature should always be 0. */ temp = ds1621_read_value(new_client, DS1621_REG_TEMP); if (temp & 0x007f) goto exit_free; @@ -232,8 +234,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); diff -Nru a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c --- a/drivers/i2c/chips/fscher.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/fscher.c 2005-01-28 15:18:53 -08:00 @@ -151,12 +151,6 @@ }; /* - * Internal variables - */ - -static int fscher_id; - -/* * Sysfs stuff */ @@ -337,7 +331,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); 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-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/gl518sm.c 2005-01-28 15:18:53 -08:00 @@ -159,12 +159,6 @@ }; /* - * Internal variables - */ - -static int gl518_id; - -/* * Sysfs stuff */ @@ -396,7 +390,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); diff -Nru a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c --- a/drivers/i2c/chips/isp1301_omap.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/isp1301_omap.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/it87.c 2005-01-28 15:18:53 -08:00 @@ -2,8 +2,8 @@ it87.c - Part of lm_sensors, Linux kernel modules for hardware monitoring. - Supports: IT8705F Super I/O chip w/LPC interface - IT8712F Super I/O chip w/LPC interface & SMbus + Supports: IT8705F Super I/O chip w/LPC interface & SMBus + IT8712F Super I/O chip w/LPC interface & SMBus Sis950 A clone of the IT8705F Copyright (C) 2001 Chris Gauthron @@ -42,10 +42,8 @@ /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; /* Insmod parameters */ @@ -106,6 +104,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; @@ -226,6 +227,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); @@ -720,7 +722,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)) @@ -824,20 +825,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); @@ -968,6 +961,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) { @@ -1128,6 +1171,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/lm75.c b/drivers/i2c/chips/lm75.c --- a/drivers/i2c/chips/lm75.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm75.c 2005-01-28 15:18:53 -08:00 @@ -73,8 +73,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 +194,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); diff -Nru a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c --- a/drivers/i2c/chips/lm77.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm77.c 2005-01-28 15:18:53 -08:00 @@ -81,8 +81,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 +293,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); diff -Nru a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c --- a/drivers/i2c/chips/lm80.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm80.c 2005-01-28 15:18:53 -08:00 @@ -141,12 +141,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) */ @@ -425,8 +419,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); diff -Nru a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c --- a/drivers/i2c/chips/lm83.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm83.c 2005-01-28 15:18:53 -08:00 @@ -150,12 +150,6 @@ }; /* - * Internal variables - */ - -static int lm83_id; - -/* * Sysfs stuff */ @@ -312,7 +306,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); diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c --- a/drivers/i2c/chips/lm85.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm85.c 2005-01-28 15:18:53 -08:00 @@ -389,9 +389,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,15 +1145,9 @@ 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))) diff -Nru a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c --- a/drivers/i2c/chips/lm87.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm87.c 2005-01-28 15:18:53 -08:00 @@ -203,12 +203,6 @@ }; /* - * Internal variables - */ - -static int lm87_id; - -/* * Sysfs stuff */ @@ -569,7 +563,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); diff -Nru a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c --- a/drivers/i2c/chips/lm90.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/lm90.c 2005-01-28 15:18:53 -08:00 @@ -190,12 +190,6 @@ }; /* - * Internal variables - */ - -static int lm90_id; - -/* * Sysfs stuff */ @@ -427,7 +421,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); diff -Nru a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c --- a/drivers/i2c/chips/max1619.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/max1619.c 2005-01-28 15:18:53 -08:00 @@ -117,12 +117,6 @@ }; /* - * Internal variables - */ - -static int max1619_id; - -/* * Sysfs stuff */ @@ -267,7 +261,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); diff -Nru a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c --- a/drivers/i2c/chips/pcf8574.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/pcf8574.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/pcf8591.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/rtc8564.c 2005-01-28 15:18:53 -08:00 @@ -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; diff -Nru a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c --- a/drivers/i2c/chips/smsc47m1.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/smsc47m1.c 2005-01-28 15:18:53 -08:00 @@ -108,7 +108,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 +132,6 @@ int init); -static int smsc47m1_id; - static struct i2c_driver smsc47m1_driver = { .owner = THIS_MODULE, .name = "smsc47m1", @@ -420,8 +417,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 diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c --- a/drivers/i2c/chips/via686a.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/via686a.c 2005-01-28 15:18:53 -08:00 @@ -815,20 +815,24 @@ return -ENODEV; } normal_isa[0] = addr; - s_bridge = dev; - return i2c_add_driver(&via686a_driver); -} -static void __devexit via686a_pci_remove(struct pci_dev *dev) -{ - i2c_del_driver(&via686a_driver); + s_bridge = pci_dev_get(dev); + if (i2c_add_driver(&via686a_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 via686a_pci_driver = { .name = "via686a", .id_table = via686a_pci_ids, .probe = via686a_pci_probe, - .remove = __devexit_p(via686a_pci_remove), }; static int __init sm_via686a_init(void) @@ -838,7 +842,12 @@ static void __exit sm_via686a_exit(void) { - pci_unregister_driver(&via686a_pci_driver); + pci_unregister_driver(&via686a_pci_driver); + if (s_bridge != NULL) { + i2c_del_driver(&via686a_driver); + pci_dev_put(s_bridge); + s_bridge = NULL; + } } MODULE_AUTHOR("Kyösti Mälkki , " diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/w83781d.c 2005-01-28 15:18:53 -08:00 @@ -175,11 +175,6 @@ : (val)) / 1000, 0, 0xff)) #define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) -#define AS99127_TEMP_ADD_TO_REG(val) (SENSORS_LIMIT((((val) < 0 ? (val)+0x10000*250 \ - : (val)) / 250) << 7, 0, 0xffff)) -#define AS99127_TEMP_ADD_FROM_REG(val) ((((val) & 0x8000 ? (val)-0x10000 : (val)) \ - >> 7) * 250) - #define ALARMS_FROM_REG(val) (val) #define PWM_FROM_REG(val) (val) #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) @@ -417,13 +412,8 @@ { \ struct w83781d_data *data = w83781d_update_device(dev); \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - if (data->type == as99127f) { \ - return sprintf(buf,"%ld\n", \ - (long)AS99127_TEMP_ADD_FROM_REG(data->reg##_add[nr-2])); \ - } else { \ - return sprintf(buf,"%d\n", \ - LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ - } \ + return sprintf(buf,"%d\n", \ + LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ } else { /* TEMP1 */ \ return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ } \ @@ -442,11 +432,7 @@ val = simple_strtol(buf, NULL, 10); \ \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - if (data->type == as99127f) \ - data->temp_##reg##_add[nr-2] = AS99127_TEMP_ADD_TO_REG(val); \ - else \ - data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - \ + data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg##_add[nr-2]); \ } else { /* TEMP1 */ \ diff -Nru a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c --- a/drivers/i2c/chips/w83l785ts.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/chips/w83l785ts.c 2005-01-28 15:18:53 -08:00 @@ -114,12 +114,6 @@ }; /* - * Internal variables - */ - -static int w83l785ts_id = 0; - -/* * Sysfs stuff */ @@ -229,7 +223,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); diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c --- a/drivers/i2c/i2c-dev.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/i2c/i2c-dev.c 2005-01-28 15:18:53 -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/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c --- a/drivers/macintosh/therm_windtunnel.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/macintosh/therm_windtunnel.c 2005-01-28 15:18:53 -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/video/adv7170.c b/drivers/media/video/adv7170.c --- a/drivers/media/video/adv7170.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/media/video/adv7170.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/adv7175.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/bt819.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/bt856.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/bttv-i2c.c 2005-01-28 15:18:53 -08:00 @@ -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/cx88/cx88-i2c.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa5246a.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa5249.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa7110.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa7111.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa7114.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa7134/saa7134-i2c.c 2005-01-28 15:18:53 -08:00 @@ -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/saa7185.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/tda7432.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/tda9840.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/tda9875.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/tea6415c.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/tea6420.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/tuner-3036.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/drivers/media/video/vpx3220.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -08:00 @@ -0,0 +1,780 @@ +/* + * 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); + atomic_dec(&__sdev->refcnt); + 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); + atomic_inc(&__ldev->refcnt); + list_add_tail(&ch->chain_entry, &__ldev->chain_list); + spin_unlock(&__ldev->chain_lock); + + atomic_inc(&dev->refcnt); + 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); + atomic_dec(&ldev->refcnt); + 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); + atomic_dec(&dev->refcnt); + 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); + atomic_dec(&ldev->refcnt); + 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); + spin_unlock(&sdev_lock); + return sdev; + } + } + spin_unlock(&sdev_lock); + + return NULL; +} + +void sc_put_sdev(struct sc_dev *sdev) +{ + atomic_dec(&sdev->refcnt); +} + +/* + * 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); + 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); + 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); + spin_unlock(&sdev->chain_lock); + return ldev; + } + } + spin_unlock(&sdev->chain_lock); + + return NULL; +} + +void sc_put_ldev(struct logical_dev *ldev) +{ + atomic_dec(&ldev->refcnt); +} + +/* + * 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); + 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. + */ + atomic_dec(&ldev->refcnt); + if (atomic_read(&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); + atomic_dec(&orig->refcnt); + + 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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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-01-28 15:18:53 -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/w1_therm.c b/drivers/w1/w1_therm.c --- a/drivers/w1/w1_therm.c 2005-01-28 15:18:53 -08:00 +++ b/drivers/w1/w1_therm.c 2005-01-28 15:18:53 -08:00 @@ -26,6 +26,7 @@ #include #include #include +#include #include "w1.h" #include "w1_io.h" @@ -128,7 +129,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 +137,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); } 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-01-28 15:18:53 -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.h b/include/linux/i2c.h --- a/include/linux/i2c.h 2005-01-28 15:18:53 -08:00 +++ b/include/linux/i2c.h 2005-01-28 15:18:53 -08:00 @@ -144,7 +144,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 */ 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-01-28 15:18:53 -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/lib/kobject_uevent.c b/lib/kobject_uevent.c --- a/lib/kobject_uevent.c 2005-01-28 15:18:53 -08:00 +++ b/lib/kobject_uevent.c 2005-01-28 15:18:53 -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,68 @@ #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; + + 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 +156,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-01-28 15:18:53 -08:00 +++ b/sound/oss/dmasound/dac3550a.c 2005-01-28 15:18:53 -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-01-28 15:18:53 -08:00 +++ b/sound/ppc/keywest.c 2005-01-28 15:18:53 -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 */